2025-01-29 09:39 AM
I am trying to capture an ADC conversion value for ADC1 channel 1 using the PA1 pin as per the STM32F429 Datasheet and have come across a couple of issues. My question has two parts, one for the actual conversion and one around the captured value.
Question 1:
No matter what I do I simply can't get the continuous and the interrupt modes to work and can only get it to work on a single-shot mode. More specifically, the heart of my periodic computation is (code is in Ada and should be fairly self-explanatory but let me know if not and I will explain):
loop
ADC.ADC1_CR2_Reg.SWSTART := Common_Types.On;
loop
exit when ADC.ADC1_SR_Reg.EOC = Common_Types.On;
end loop;
Common_Values.Measured_ADC_Value := ADC.ADC1_DR_Reg;
end loop;
This is the periodic loop that runs constantly (naturally, waiting for the desired period for every iteration) whilst the setup that runs just once is the following:
ADC.ADC1_CR1_Reg.EOCIE := Common_Types.On;
ADC.ADC1_CR2_Reg.ADON := Common_Types.On;
ADC.ADC1_CR2_Reg.CONT := Common_Types.On;
Now, running the above code results in the following: the EOC flag turns on, the interrupt handler is called once and then EOC stays off for ever and no further interrupts are generated and basically the program gets stuck in the inner loop (yeah, I can apply some timing around that to kill the endless loop but let's ignore that for the moment and my goal is to update a shared volatile value from within the interrupt handler anyway).
As mentioned, the only mode I could get it to work is in the single-shot mode where CONT = OFF (and also EOCIE = OFF though that shouldn't matter, I don't think?).
FWIW, I tried a number of (non-exhaustive) permutations using the above flags and observed the following behaviour:
EOCIE | ADON | CONT | SWATART | Result |
OFF | ON | OFF | Set ON in every iteration | EOC turns ON, different value stored in DR as the potentiometer is rotated |
OFF | ON | ON | Set once to ON prior to periodic loop | EOC turns ON once and then stays OFF for ever |
ON | ON | ON | Set ON in every iteration | EOC turns ON once, interrupt handler is called just once and then EOC stays OFF for ever |
ON | ON | OFF | Set ON in every iteration | EOC turns ON once, interrupt handler is called just once and then EOC stays OFF for ever |
In the above, the difference between set-in-every-iteration and set-once is the difference between this:
loop
ADC.ADC1_CR2_Reg.SWSTART := Common_Types.On;
loop
exit when ADC.ADC1_SR_Reg.EOC = Common_Types.On;
end loop;
Common_Values.Measured_ADC_Value := ADC.ADC1_DR_Reg;
end loop;
and that:
ADC.ADC1_CR2_Reg.SWSTART := Common_Types.On;
loop
loop
exit when ADC.ADC1_SR_Reg.EOC = Common_Types.On;
end loop;
Common_Values.Measured_ADC_Value := ADC.ADC1_DR_Reg;
end loop;
The reference manual mentions the following:
In continuous conversion mode, the ADC starts a new conversion as soon as it finishes one.
This mode is started with the CONT bit at 1 either by external trigger or by setting the
SWSTART bit in the ADC_CR2 register (for regular channels only).
After each conversion:
If a regular group of channels was converted:
–The last converted data are stored into the 16-bit ADC_DR register
–The EOC (end of conversion) flag is set
–An interrupt is generated if the EOCIE bit is set
Which leads me to believe that after setting CONT then SWSTART needs to be set just once for the continuous mode to kick-in, but I may have misinterpreted that. So, a bit confused as to why the above setup doesn't work as expected.
Question 2:
How is the converted value in DR meant to be interpreted? Is it meant to be read something along the lines of DR * Step_Size? (with step size being Vin / 2^16). I couldn't find that anywhere across the RM, UM and DS documents.
Though not massively relevant for this I guess, I have nevertheless verified with a multimeter that the range of
0V - Vcc (i.e. 3V) of my potentiometer is fully functional.
Any pointers would be much appreciated. - Thanks.
2025-01-29 03:20 PM
Q2) For a 12-bit value, the voltage is COUNTS * VREF / 4096.
Couldn't parse the first question. What behavior do you want? Do you want a one-shot conversion or do you want continuous conversions with an interrupt occurring after every conversion? Or something else?
2025-01-30 01:01 AM - edited 2025-01-30 01:01 AM
Ah! Missed that on the DS. Thank you.
Regarding Q1, I am after setting up a continuous mode i.e. I want to start the conversions once and then have the interrupt called upon each conversion without the need to set SWSTART on each iteration. What I am observing though is that having turned the ADC module on (i.e. ADON = ON) and then CONT = ON and EOCIE = ON then the interrupt handler is called just once, EOC turns-on just once and then stays off for ever after the first conversion.
When I turn EOCIE off and turn SWSTART on, upon every iteration then EOC turns off after each conversion and I can see different values stored in DR as I rotate the potentiometer.
FWIW, I'm using the following address definitions:
-- Address definitions
ADCS_Base_Address : constant := 16#4001_2000#;
ADC1_Base_Address : constant := ADCS_Base_Address + 16#0000_0000#;
ADC1_SR_Address : constant := ADC1_Base_Address + 16#00#;
ADC1_CR1_Address : constant := ADC1_Base_Address + 16#04#;
ADC1_CR2_Address : constant := ADC1_Base_Address + 16#08#;
ADC1_SMPR1_Address : constant := ADC1_Base_Address + 16#0C#;
ADC1_SMPR2_Address : constant := ADC1_Base_Address + 16#10#;
ADC1_SQR1_Address : constant := ADC1_Base_Address + 16#2C#;
ADC1_SQR2_Address : constant := ADC1_Base_Address + 16#30#;
ADC1_SQR3_Address : constant := ADC1_Base_Address + 16#34#;
ADC1_DR_Address : constant := ADC1_Base_Address + 16#4C#;
and am fairly confident I've done the mapping right (i.e. record representation clauses in Ada) but I can grab the raw bits in gdb to verify that, if you've got an address to share.
Thanks.
2025-01-30 06:37 AM
The interrupt will fire when each conversion is done.
Note that this adds up to a lot of interrupts. Could be that you're misinterpreting what is happening due to this. If the interrupt handler isn't quick enough, the main loop will never get anywhere.