I finally found the actual hardware documentation for Lepton’s STM32G031 STM32G0 Series - PDF Documentation and the ADC is really easy to use if you bypass the ridiculously overcomplicated HAL and LL libraries and just work with the registers directly. Seriously, what even is the point of a library if it makes it more difficult to figure out what is the proper sequence of operations to accomplish a task, while wasting massive amounts of CPU cycles and flash space, and is still different for each line of stm32 chips?
I’ve added a weakly bound function ReadLinearHalls that does the analogRead operations, so you can override it with custom code on platforms with bad analogRead implementation. The register #defines here are my own, so this code will not compile directly, but shows how little work actually needs to be done to operate the ADC.
void ReadLinearHalls(int pinA, int pinB, int *a, int *b)
{
ADCISR = ADCISR_ADRDY | ADCISR_CCRDY; // Clear flags
ADCCFGR1 = ADCCFGR1_WAIT; // Wait until ADCDR is read before starting second conversion
ADCCFGR2 = ADCCFGR2_OVSE | ADCCFGR2_PVSR(3) | ADCCFGR2_OVSS(4); // 16x oversampling, shifted down 4 bits
ADCCHSELR = (1<<pinA)|(1<<pinB);
ADCCR |= ADCCR_ADEN; // Enable ADC
while(!(ADCISR & ADCISR_ADRDY) && !(ADCISR & ADCISR_CCRDY));
ADCCR |= ADCCR_ADSTART;
while(!(ADCISR & ADCISR_EOC));
sensor.lastA = ADCDR; // Reading ADCDR clears the end-of-conversion flag
while(!(ADCISR & ADCISR_EOC));
sensor.lastB = ADCDR;
ADCCR |= ADCCR_ADDIS; // Disable ADC (saves power, and would need re-armed by next frame anyway (100us t-idle from datasheet)
}
Also a couple things needed in setup()
RCCAPBENR2 |= RCCAPBENR2_ADCEN; // Enable ADC clock
ADCCR = ADCCR_ADVREGEN; // Enable voltage regulator
delayMicroseconds(20); // Voltage regulator startup time from STM32G031 datasheet
But when used together with hardware current sense, you will have to go through the HAL library and be careful not to step on the toes of the current sense ADC configuration.
The pinA and pinB variables refer to ADC channels in this case rather than port pin names like PA1, so I had to remove the pinMode(pin, INPUT); calls in LinearHall::init. But that should be fine since pins are typically input at startup, and in my case it’s convenient if nothing touches them because on STM32, digital input and analog input are separate modes, and analog is the default. You can always configure them manually before calling sensor.init if there are any platforms where it matters.
I’ve also got it going with the fast atan2 I linked in post #12. I’ve gone from over 700 microseconds for the angle reading (250 per analogRead, 200 for atan2) to 35 (7 for the ADC operations, 28 for atan2). About 2000% speedup :lol: And about 5kb of flash saved. And for the cost of 6 more microseconds I can have 8x oversampling to significantly improve the signal quality.
@nanoparticle If it’s ok with you, I’ll do a pull request with this in the main repository sensors folder, rather than drivers repository. Though I feel terrible replacing your name as the original contributor