2015-09-18 01:43 AM
Hi,
I would be grateful for some advice on Sampling logic-level signal with a timer.I haven't done embedded programming in a very long time and so have little experience with the current STM32 offering - and at the moment I am still waiting on Hardware to program. The FW will involve sampling at high frequency, and I see from the Forum that others have run into problems with their approach as regards over saturating the micro etc. I would be grateful if those with experience could tell me if the following approach seems reasonable. Basically I want to use a timer at 40kHz to sample the level of a pin and write it to an array element, incrementing along once every 25 uS, in an STM32F417 micro. Systick would remain at the usual 1mS. I would be using the cube TIM_timebase example for G-Eval board as a starting point and adjusting the timer and periods to achieve the above rate. Is that a bit naive or does it sound ok? Any ideas as to what kind of rate the above approach could be pushed to, i.e 0.5 MHz?Thanks.2015-09-18 02:17 AM
40KHz sampling is not an issue for that microcontroller. The question is where are you going to write that much data? Your SRAM will run out in couple of seconds. Do you have some kind of external memory?
2015-09-18 02:48 AM
2015-09-18 05:32 AM
Since you are looking at one pin my approach would be to treat it as an A/D conversion. Connect your signal to an ADC input, set up the ADC for TIM triggered ample rate (you can go far higher than 40KHz) and use DMA to read the samples. Data reduction is picking an arbitrary level for assert and deassert to convert to binary. Use BitBand to write out the result bit to a word array that maps back to packed bits.
This offloads data capture from interrupts. With an F4 the data capture time is almost free since you can run the DMA in parallel if you are careful about assigning the DMA buffer to reduce SRAM bus collisions with the rest of the program. With a circular buffer you can reduce one half the buffer while capturing the other half, using DMA half transfer events. Jack Peacock2015-09-18 05:33 AM
You're going to have a headache as the interrupt rates head into the 100's of KHz. The way to sample pins at high/fixed rates is to use a TIM to drive a DMA action (GPIO bank to memory), and decimate the interrupt rate using the HT and TC interrupts of the DMA
2015-09-20 01:39 AM
Clive,
Thanks for your suggestion, but I have a query on NTDR and transfer callbacks (for the 40kHz case). I would like to set up acontinuous
DMA transfer from a single pin to a incrementing circular buffer, so that I have, say, 1 second of signal logic level history. As the DMA increments, I would like to know what was the last updated array element, and have a function called to do some time/sync-critical processing (elsewhere) - i.e. called after the latest array element transfer,to be completed before the next DMA array element transfer. For a starting point, I was planning to use your code at I was wondering if you could please show me some code to do a per element transfer callback,reporting the last transferred array element index - maybe based on NTDR. From this callback I could call another function to do some time critical functions elsewhere. Also, a newbie DMA question - is it ok to read (just read) a value from a circular buffer that is continously being updated? Especially if you explicitly wait until an array element is reported before making the read? What if you don't explicitly wait and just read - is there a risk of corrupted data or is access atomically locked to be either old or latest data? ...and if doing a dma transfer memory to peripheral continuous, can you write to an array that is a live DMA source, or must you write to another array and then switch it over? Thanks2015-09-20 04:06 AM
Generally that's why I use HT/TC (Half Transfer/Transfer Complete) so I split the buffer into two halves (ping/pong) and work on the half that's just finished, and is thus not ''live'', and prone to change underneath me.
You then have about that half time, less some safety margin to process the data. Yes, you could probably check the pointer, and chase it, but you'd need to be very wary. I'd want to be able to process the data significantly faster than it's generated, if you're approaching parity, you need to rethink what you're doing.2015-09-20 04:16 AM
There is not way to get locked/atomic access, the DMA operates autonomously from the core. You should tell the compiler the data array is volatile. You can stop the timer or disable the DMA, of course, but that is likely to create more problems than it solves.
Some parts permit a ''double buffering'' DMA mode which is a bit like the ping/pong method but with independent/non-linear buffers, and you can perhaps juggle three or more buffers, or chain them, but that adds more complexity than I care for.2015-09-21 06:00 AM
Clive,
Thanks. If you consider the basic example of an ADC continuously dma transferring its value to a location, such as in the ADC_RegularConversion_DMA example, how did ST expect users, in a practical sense, to do something practical with the transferred data?It kind-of implies that it is safe just to read from the value that is transferred in - because otherwise what use is that DMA configuration/example? Do you think a situation could arise where you read out the value mid way through an element update and get corrupted data?2017-05-05 12:28 PM
You can use the DMA in circular mode and store 1 second of data at this rate. In the same time, you can get SysTick IRQ @ 1 ms, read DMA->NDTR (remaining data till end of the buffer) and process the data between previous NDTR sample and the new one.
Tested, working, used as intermediate buffer for UART Rx reception with AT command parsing engine behind :)