HAL_ADC_PollForConversion - what exactly is it for? - stm32

I've been tinkering around STM32 (F103RB) for a couple of weeks now and one thing I don't get is
HAL_ADC_PollForConversion
function purpose. I mean, I don't see any impact of this function on ADC readings. Here's my code example:
Version 1 (with PollForConversion on)
while (1)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
uint32_t value = HAL_ADC_GetValue(&hadc1);
float voltage = 3.3f * value / 4096.0f;
printf("ADC = %lu (%.3f V)\n", value, voltage); //send the value via UART
HAL_Delay(250);
}
Version 2 (with PollForConvertion off)
while (1)
{
HAL_ADC_Start(&hadc1);
//HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
uint32_t value = HAL_ADC_GetValue(&hadc1);
float voltage = 3.3f * value / 4096.0f;
printf("ADC = %lu (%.3f V)\n", value, voltage); //send the value via UART
HAL_Delay(250);
}
As far as my observations go, it doesn't really matter whether I use PollForConversion or not - the readings on the UART monitor look the same (altough I am not 100% certain they actually are the same). Continous mode is disabled. What am I missing here?

After you start ADC with HAL_ADC_Start(), hardware starts ADC conversion. This conversion takes some time. Exact time depends on your ADC configuration in Cube, the greater value of ADC prescaler and cycle count the longer it takes.
After conversion is completed, EOC flag in ADC hardware is set and measured value is placed in register. You can read that value with HAL_ADC_GetValue() function. But if you read it before end of conversion, you will probably get data that is corrupted or an old value from previous measurement.
That's why you should always wait untill EOC flag is set - this is exactly what HAL_ADC_PollForConversion does.
In your example without polling you probably read value from previous measurement before the current one ended. Or maybe HAL functions that interact with hardware are slow enough to actually read data when EOC flag is set anyway. You can increase number of ADC clock cycles in Cube to maximum and try it then, you should get a value from last measurement.

Related

Optimize power consumption with STM32L4 ADC

I'm working on a firmware development on a STM32L4. I need to sample an analog signal at around 200Hz. So basically one analog to digital conversion every 5ms.
Up to now, I was starting the ADC in continuous conversion mode, triggered by a timer. However this prevents to put the STM32 in Stop mode in between conversions, which would be very efficient in terms of power consumption since 99%+ ot the time the product has nothing to do.
So my idea is to use the single conversion mode: use a low power timer to wakeup the product from Stop mode every 5ms, launch a single conversion in the LPTIM interrupt handler (waiting for ADC end of conversion in polling), and go back to Stop mode.
Do you think it makes sense or do you see problems to proceed like this ? I'm not sure about polling for a single ADC conversion inside a handler, what do you think ? I think a single conversion on one channel should be pretty fast (I run at 80MHz, the datasheet mentions a maximum sampling time of 8us)
Do I have to disable/enable ADC (the bit ADEN) between each single conversion ?
Also, I have to know how long a single conversion lasts to assess whether the solution is interesting or not. I'm confused about the sampling time (bits SMP). The reference manual states: "This sampling time must be enough for the input voltage source to charge the embedded capacitor to the input voltage level." What is the way to find the right SMP value ?
There are no problems with the general idea, LPTIM1 can generate wakeup events through the EXTI controller even in Stop2 mode.
I'm not sure about polling for a single ADC conversion inside a handler, what do you think ?
You might want to put the MCU in Sleep mode in the timer interrupt, and have the ADC trigger an interrupt when the conversion is complete. So disable SLEEPDEEP in the timer interrupt, and enable it in the ADC interrupt.
What is the way to find the right SMP value ?
Empirical method: start with the longest sampling time, and start decreasing it. When the conversion result significantly changes, go one or two steps back.

ESP8266 + Micropython: Why do I keep getting the same value with periodic i2c reads?

I am writing some simple code using MicroPython running on a Digistump Oak, which is basically an ESP8266 breakout board. I'm trying to understand the behavior that I see when performing periodic reads of the sensors via i2c.
The following code (which reads the value of the ACCEL_XOUT_H and ACCEL_XOUT_L registers) works just fine:
>>> from machine import Pin, I2C
>>> bus = I2C(scl=Pin(2), sda=Pin(0))
>>> while True:
... h, l = bus.readfrom_mem(0x68, 0x3b, 2)
... print (-((((h<<8)+l)^0xFFFF) + 1) if (h & (1<<7)) else (h<<8)+l)
(That print statement is just performing the conversion from two's complement.)
As expected, that prints out values from the accelerometer that change in approximately real time as I move the imu around.
But if I introduce a delay into the loop, such as...
>>> import time
>>> from machine import Pin, I2C
>>> bus = I2C(scl=Pin(2), sda=Pin(0))
>>> while True:
... h, l = bus.readfrom_mem(0x68, 0x3b, 2)
... print (-((((h<<8)+l)^0xFFFF) + 1) if (h & (1<<7)) else (h<<8)+l)
... time.sleep(1)
...I see some very strange behavior. The values returned by the i2c read operation continue to remain the same for many iterations after the imu has changed orientation. I'm at a loss as to what is going on here: the i2c read operations read from the registers on the imu, which according to the documentation are updated at the sampling rate, which in a default configuration is going to be 1Khz. I don't see anything in the code or data path that could be latching or caching these values somehow.
This is the documentation on the accelerometer registers, as found in the Register Map and Descriptions document:
These registers store the most recent accelerometer measurements.
Accelerometer measurements are written to these registers at the
Sample Rate as defined in Register 25.
The accelerometer measurement registers, along with the temperature
measurement registers, gyroscope measurement registers, and external
sensor data registers, are composed of two sets of registers: an
internal register set and a user-facing read register set. The data
within the accelerometer sensors’ internal register set is always
updated at the Sample Rate. Meanwhile, the user-facing read register
set duplicates the internal register set’s data values whenever the
serial interface is idle.
Since I'm sleeping between read calls, I'm pretty sure the i2c serial interface is idle by any definition, and I don't see anything else seems relevant to this behavior.
Do you have any suggestions as to what could be going on here?

Delay interfacing Arduino and Simulink

I am trying to read data from potentionmeter using an arduino microcontroller (tried both arduino UNO, arduino FIO) and using serial communication interface it to Simulink (I tried baud rates ranging from 57600-921600).
Here is the Arduino source code:
/*
AnalogReadSerial
Reads an analog input on pin 0, prints the result to the serial monitor.
*/
#define ana_pin A0
void setup() {
analogReference(DEFAULT);
Serial.begin(57600);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input on analog pin 0:
int sensorValue = analogRead(ana_pin);
// print out the value you read:
Serial.print(sensorValue);
// delay(500); // delay in between reads for stability
}
I interfaced it with Tera Term software and there is instantaneous change of values corresponding to 3 V or 0V.
However when I tried to interface it with Simulink model using instrument control toolbox:
there is a 10 second lag when value changes from ASCII representation of 3V to 0V
The block sample time is 0.01 seconds and the model configuration parameters are adjusted accordingly (I tried it for 1 second or more and the delay still remains. Also, I was able to record data from another sensor and LPC1768 development board without any delay.
I also tried it with Arduino support libraries in Simulink:
And it seems that no data is received, as you can see from Scope1 in the png file the status signal is always 0. I have also attached hardware implementation properties from Arduino block in Simulink:
Could you help me understand what is going on and how to solve this issue?
#Patrick Trentin -
I get a delay of 4 seconds when I use baud rates of 230400, 460800 and 921600.
For baud rate of 57600, 115200 I get a delay of 10 seconds.
Thank you for pointing it out I did not focus on that previously.
However since I will be using the sensor in an application which accurately needs reading every 0.01 sec. I dont think I can work with 4 sec delay.

Understanding some ADC instructions

I am trying to program an adc in stm32f4. I want to know what are the roles of these five instructions?
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right
ADC_Mode_Independent The ADC functions independently of others. Other modes allow two ADC to be read at exactly the same time (for power measurement) or interleaved (2 or 3 ADC cooperate to read the same channel more often)
ADC_Prescaler_Div2 - How fast the ADC works its SAR algorithm
ADC_DMAAccessMode_Disabled - DMA provides the ability to take a number of readings and have them automatically put into a table in memory
ADC_TwoSamplingDelay_5Cycles - There are two registers, this one one is a delay between successive readings, the other is the sampling time, the time taken to physically sense the voltage on the pin. You must have a low impedance source to use shorter sampling. explained in the manual. Some processors can read the same pin more than once before stepping to the next pin, hence the delay read the ADC accuracy appnotes.
ADC_DataAlign_Right

STM32F427's USART1 sometimes sets 8th data bit as if it would be parity bit

I'm working with STM32F427 UASRT1 via the following class:
void DebugUartOperator::Init() {
// for USART1 and USART6
::RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
// USART1 via PORTA
::RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
::GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
::GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
GPIO_InitTypeDef GPIO_InitStruct;
// fills the struct with the default vals:
// all pins, mode IN, 2MHz, PP, NOPULL
::GPIO_StructInit(&GPIO_InitStruct);
// mission-specific settings:
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
::GPIO_Init (GPIOA, &GPIO_InitStruct);
USART_InitTypeDef USART_InitStruct;
// 9600/8/1/no parity/no HWCtrl/rx+tx
::USART_StructInit(&USART_InitStruct);
USART_InitStruct.USART_BaudRate = 921600;
USART_InitStruct.USART_WordLength = USART_WordLength_9b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_Odd;
::USART_Init(USART1, &USART_InitStruct);
::USART_Cmd(USART1, ENABLE);
}
void DebugUartOperator::SendChar(char a) {
// wait for TX register to become empty
while(::USART_GetFlagStatus(USART1, USART_FLAG_TXE) != SET);
::USART_SendData(USART1, static_cast<uint8_t>(a));
}
The problem is that every now and then USART starts ignoring actual 8th data bit and setting it as a parity bit (odd parity, to be specific). The strangest of all that it sometimes happens even after a long poweroff, without any prior reprogramming or something. For example yesterday evening it was all OK, then next morning I come to work, switch the device on and it starts working the way described. But it's not limited to this, it may randomly appear after some next restart.
That effect is clearly visible with the oscilloscope and with different UART-USB converters used with diffrent programs. It is even possible, once this effect have appeared, to reprogram a microcontroller to transmit test data sets. For example, 0x00 to 0xFF in endless cycle. It does not affect the problem. Changing speeds (down to 9600 bps), bits per word, parity control does not help - the effect remains intact even after repropramming (resulting for example in really abnormal 2 parity bits per byte). Or, at least, while UASRT is being initialized and used in the usual order according to my program's workflow.
The only way to fix it is to make the main() function do the following:
int main() {
DebugUartOperator dua;
dua.Init();
while(1) {
uint8_t i;
while(++i)
dua.SendChar(i);
dua.SendChar(i);
}
}
With this, after reprogramming and restart, the first few bytes (up to 5) are transmitted rotten but then everything works pretty well and continues to work well through further restarts and reprograms.
This effect is observed on 2 different STM32F427s on 2 physically different boards of the same layout. No regularity is noticed in its appearance. Signal polarity and levels conform USART requirements, no noise or bad contacts are dectected during investigation. There seems to be no affection to UASRT1 from the direction of other code used in my program (either mine or library one) or it is buried deeply. CMSIS-OS is used as RTOS in the project, with Keil uVision 5.0.5's RTX OS.
Need help.
In STM's you can specify wordlength for usart / uart transmission but wordlength is a sum of data bits and bit parity. So if you would like to have 8 bit data and even parity bit, you have to specify UART_WORDLENGTH_9B andUART_PARITY_EVEN.
You can also have 9 bits of data, with no parity. In reference manual for F427 section 30.6.4, Bit 12 we see that it should be possible to set 9 data bits, but term data bits is also applicable to parity bit.
Bit 12M: Word length
This bit determines the word length. It is set or cleared by software.
0: 1 Start bit, 8 Data bits, n Stop bit
1: 1 Start bit, 9 Data bits, n Stop bit
Final answer is in 30.6.4, Bit 10
This bit selects the hardware parity control (generation and
detection). When the parity control is enabled, the computed parity is
inserted at the MSB position (9th bit if M=1; 8th bit if M=0) and
parity is checked on the received data. This bit is set and cleared by
software. Once it is set, PCE is active after the current byte (in
reception and in transmission).