ADC conversion blocks in osless HAL
Posted: Tue May 03, 2016 4:54 pm
Hello,
I'm trying to use HAL only for a simple project on a STM32 nucleo-F446RE board.
A minimal example where I try to query two input pins using the ADC blocks.
With the debugger I could determine that the adcConvert() function was blocking in osalThreadSuspendS(), where it appears to keep iterating through the first osalSysUnlock() call in the while loop.
Comment out the adcConvert() statement, and the board runs fine and the led alternates. Add the statement in the main loop, and the board gets stuck in infinite wait.
I'm quite clueless, anybody has ideas?
I was first trying to do asynchronous conversion, but as the callbacks were never called, I reduced it to an inline conversion for testing.
I'm trying to use HAL only for a simple project on a STM32 nucleo-F446RE board.
A minimal example where I try to query two input pins using the ADC blocks.
Code: Select all
/*
*/
#include "hal.h"
/*
ADC setup
*/
// Create buffer to store ADC results. This is
// one-dimensional interleaved array
#define ADC_BUF_DEPTH 2 // depth of buffer
#define ADC_CH_NUM 2 // number of used ADC channels
static adcsample_t samples_buf[ADC_BUF_DEPTH * ADC_CH_NUM]; // results array for adc1
static ADCConfig adccfg = {0};
/*
* Callback invoked when ADC conversion is done
*/
void adccb(ADCDriver *adcp, adcsample_t *buffer, size_t n) {
if (adcp->state == ADC_COMPLETE) {
toggle_led();
}
}
void adcerr(ADCDriver *adcp, adcerror_t err) {
}
#define ADC1_CH1 0
#define ADC1_CH2 2
static ADCConversionGroup adccg1 = {
// this 3 fields are common for all MCUs
// set to TRUE if need circular buffer, set FALSE otherwise
TRUE,
// number of channels
(uint16_t)(ADC_CH_NUM),
// callback function, set to NULL for begin
adccb, //NULL,
// error callback
adcerr,
// Resent fields are stm32 specific. They contain ADC control registers data.
// Please, refer to ST manual RM0008.pdf to understand what we do.
// CR1 register content, set to zero for begin
0,
// CR2 register content, set to zero for begin
0,
// SMRP1 register content, set to zero for begin
0,
// SMRP2 register content, set to zero for begin
0,
// SQR1 register content. Set channel sequence length
((ADC_CH_NUM - 1) << 20),
// SQR2 register content, set to zero for begin
0,
// SQR3 register content. We must select 2 channels
(ADC1_CH1 | (ADC1_CH2 << 5)),
};
void toggle_led(void) {
if palReadPad(GPIOA, GPIOA_LED_GREEN) {
palClearPad(GPIOA, GPIOA_LED_GREEN);
} else {
palSetPad(GPIOA, GPIOA_LED_GREEN);
}
}
void loop(void) {
toggle_led();
// one-shot conversion
adcConvert(&ADCD1, &adccg1, &samples_buf[0], ADC_BUF_DEPTH);
osalThreadSleepMilliseconds(500);
}
/*
* Application entry point.
*/
int main(void) {
/*
* System initializations.
* - HAL initialization, this also initializes the configured device drivers
* and performs the board-specific initializations.
*/
halInit();
/*
* Enabling interrupts, initialization done.
*/
osalSysEnable();
/*
* Setup adc input pins for analog input
*/
palSetPadMode(GPIOA, GPIOA_PIN0, PAL_MODE_INPUT_ANALOG); // adc channel 0, pa0, adc1 ch1
palSetPadMode(GPIOA, GPIOA_PIN1, PAL_MODE_INPUT_ANALOG); // adc channel 1, pa1, adc2 ch1
// Enable led
palSetPad(GPIOA, GPIOA_LED_GREEN);
adcInit(); // not really necessary as halInit() already does this
// Activate ADC1 peripheral
adcStart(&ADCD1, &adccfg);
/*
* Main loop
*/
while (true) {
loop();
}
}With the debugger I could determine that the adcConvert() function was blocking in osalThreadSuspendS(), where it appears to keep iterating through the first osalSysUnlock() call in the while loop.
Comment out the adcConvert() statement, and the board runs fine and the led alternates. Add the statement in the main loop, and the board gets stuck in infinite wait.
I'm quite clueless, anybody has ideas?
I was first trying to do asynchronous conversion, but as the callbacks were never called, I reduced it to an inline conversion for testing.