#pragma once
#include <stm32f10x.h>
#include "usb.h"
/* Hardware:
A3 T2C4 PWM-Ausgang, steuert die Bremskraft
A4 frei
A5 SCK1 Messschieber-Takt vom LM393 ¹
A6 (ADC6) Verdreh-Sensor (Mikrotaster) ¹
A7 MOSI1 Messschieber-Daten vom LM393 ¹
(A11 USB D-)
(A12 USB D+)
B0 ADC8 Kraftmessdose, ≥ 100 kSa/s
B1 ADC9 Potenziometer
B10 TxD3 Interface der Linak-Steuerung
B11 RxD3 Interface der Linak-Steuerung
(B12 Blaue LED, low-aktiv)
¹ erfordert chip-internen Pullup
Verwendung der Peripherie:
ADC1 Kraftmessdose (schnell und kontinuierlich)
ADC2 Potenziometer (gelegentlich)
USART3 Linak-Servo
SPI1 Messschieber
Timer2 PWM-Ausgang
Timer3 Triggerverzögerung für ADC1
Timer4 Endeerkennung für SPI1
DMA1CH1 ADC1 (Kraftmessdose)
DMA1CH2 SPI1 (Messschieber)
USB HID+WebUSB
*/
void delay(uint32_t);
void set_sysclock();
void revert_sysclock();
void idle();
// Alle Reports verwenden eine Report-ID.
// Konstruktoren vermeiden für Zusammenfassung in Union
struct Report{
byte repid;
operator byte*() {return &repid;} // Als Ganzes ansprechen
};
extern struct RepF:public Report{
byte flags; // Bit 0 = Benutze folgende Bremskraftvorgabe
int16_t brems; // Bremskraftvorgabe, 0..4095
int16_t k1,k2; // Triggerschwellen für Kraftstoß-Oszillogramm-Report, 0..4095
int16_t tp,tg; // Prätrigger, Gesamtzeit (in Samples)
static constexpr int16_t tg_max=500;
}repF;
struct Simplestat{ // size: 8 (ohne Quadratsumme)
int16_t min,max;
int32_t sum;
// int64_t qsum;
void add(int16_t val) {
if (min>val) min=val;
if (max<val) max=val;
sum+=val;
// qsum+=(int32_t)val*val; // Wie teuer ist diese Multiplikation?
}
void reset() {min=32767; max=-32767;sum=0;/*qsum=0;*/}
};
namespace adc{
void init();
void reloadFeature(byte); // bei Änderung von repF: Triggerschwellen nachführen
void arm();
void manualtrigger();
unsigned collect(int16_t*,unsigned);
uint16_t get_poti(Simplestat&); // liefert min, max, Mittelwert
// uint32_t getTriggerState();
}
extern struct RepI:public Report{ // size: 22
byte flags; // Bits:
// 7 = Dirty (bei Interrupt-In stets 1, bei Abfrage via Control-Pipe je nachdem) *
// 6 = drohender Überlauf der Statistik (durch fehlenden Messschieber) *
// 5 = ?
// 4 = ?
// 3:2 = Phase der Triggerung:
// 0 = Abwarten von <repF.tp> Samples (nur wenn repF.tp>0)
// 1 = Warten auf erste Triggerbedingung (Unterschreitung <repF.k1>)
// 2 = Warten auf zweite Triggerbedingung (Überschreitung <repF.k2>)
// 3 = Abwarten von <repF.tg-repF.tp> Samples
// 1 = Neuer Wert vom Messschieber *
// 0 = Zustand des Verdreh-Tasters
uint16_t n; // Anzahl Statistik-Einträge (betrifft p.sum und k.sum) *
Simplestat p; // Poti(×2) *
Simplestat k; // Kraft(×4) *
int16_t weg;
void reset(); // * = Dieses Bits/Werte werden nach Interrupt-Transfer gelöscht
}repI;
extern struct RepLinak:public Report{
byte addr; // Bit 7 = lesen
uint16_t value;
}repLinak;
extern struct RepStoß:public Report{
byte flags; // Bit 7 = k1-Trigger wurde erfüllt; 6:0 = Füllung
int16_t kraft[250]; // A/D-Werte des Kraftstoßes
inline void reset() {flags=0; adc::arm();} // nach Absenden des Reports: Erneut scharfmachen
inline void collect() {
adc::collect(kraft,elemof(kraft));
flags=0x80|elemof(kraft);
} // Nach verzögertem Trigger: Daten aus DMA-Puffer einsammeln
}repStoß;
struct RepReboot:public Report{
byte doit; // Nur wenn 1
};
/* Simple function pointer type to call user program */
typedef void (*func_ptr_t)();
extern func_ptr_t vtbl[16+56];
namespace usb{
extern byte DevStatus; // Bit 0: SelfPower, Bit 1: RemoteWakeup
extern byte DevConfig;
void shutdown();
void init();
// Diese Routinen können blockieren und rufen dann idle()!
// Rekursion ist zu vermeiden!
void poll();
bool send0(const byte*,unsigned);
bool send(byte,const byte*,unsigned);
// Der letzte Parameter steuert ob Short-Packets okay sind, und ist ein Zeiger
// auf die empfangenen Bytes.
// Diese Routine blockiert und ruft idle()!
bool recv(byte,byte*,unsigned,unsigned* =nullptr);
}
// Callbacks
bool onSetReport(uint16_t,uint16_t);
bool onGetReport(uint16_t,uint16_t);
#define BB_BIT(a,b) (*(volatile uint32_t*)(((uint32_t)&(a)&0xFF000000)+0x02000000+((uint32_t)&(a)&0x00FFFFFFF)*32+(b)*4))
#define LED_INIT() BB_BIT(GPIOB->CRH,16) = 1 // output open drain
#define LED BB_BIT(GPIOB->ODR,12) // 0 = on, 1 = off
namespace caliper{
void init(); // SPI1 und DMA1CH2 aktivieren
}
namespace pwm{
void init();
inline void out(uint16_t v) {TIM2->CCR4=v;}
}
| Detected encoding: UTF-8 | 0
|