implement maximum speed adc to usb transfert
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2018-12-25 10:44 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2018-12-27 12:59 AM
Some embedded programming know how maybe missing here and following steps. Adc value can be stored in uint16_t 16 bit variable, made of 2x8 bytes. Just push these 2 bytes raw ro usb without any formatting by sprintf. And decidd if you send bit 0..7 or bit8..15 first.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2018-12-27 01:16 AM
Hi Bob,
I am using continuous conversion mode
hadc.Init.ContinuousConvMode = ENABLE;
and a sampling time of 239.5 cycles :
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
so I don't think I need to poll for conversion
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2018-12-27 01:22 AM
I am totaly agree with you KIC8462852 EPIC204278916, but it is always more clear with a piece of real code, because usually what's causing troubles are the details.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2018-12-27 03:03 AM
Download Teraterm-like utility and using the com port, no need to make complex strings, just output the data and forget the 8 or 64 bytes granularity.
You'll have to create a char SW FIFO to accumulate the text you want to push to the console. Add markers like "/n to go to next like and be able to save your console output as CSV Excel format. send the data in plain HEXA format text first: every 16 bit ADC value will correspond to 4 char (16 bit) output. add a space between hex data and you'll be able to feed a spreadsheet. If you try to optimize the bandwidth and datarate, you'll be defocusing from having a baseline reference. Break the problem in smaller pieces to overcome step by step.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2018-12-27 07:41 AM
> "so I don't think I need to poll for conversion"
Yes, you do. At the very least you need to check the EOC (end of conversion) flag and only call HAL_ADC_GetValue() when that flag is set (calling GetValue() will then clear that flag). This is what the HAL_ADC_PollForConversion() does. If you continually read the ADC's data register, which is what HAL_ADC_GetValue() does, you will keep reading the SAME value from the previous conversion until the next conversion happens. And the number of times you get that SAME value will not be consistent, because after some GetValue() calls you will end up calling the USB transmit function, or a USB interrupt will happen, or some other interrupt (system tick, etc.).
Which brings me to another point I had overlooked before. I don't know which CPU you are using, or what your clock speeds are, or what your conversion clock rate is (you only showed the "sample time" value). BUT... it is quite possible that all of the USB code (most of which runs from interrupts) could delay your polling loop so that you miss a sample. Ideally you would use either interrupts or DMA to transfer the ADC samples into a buffer. Then your main polling loop could take data from that buffer, format however you wish and send to the USB interface. If using interrupts you need to ensure that the ADC interrupt has a higher priority than the USB interrupt.
There are a few threads on this forum about using DMA with UARTS. The same idea applies to the ADC. Look for those threads and see if you can apply those ideas to your ADC.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2018-12-27 10:10 AM
KIC8462852 EPIC204278916, do you have a little piece of code, only one instruction to begin if you want.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2018-12-27 10:44 AM
@S.Ma - What is the *significant* difference or advantage of outputting 4 ASCII hex characters followed by a "\r" or space, and outputting an ASCII decimal representation of the same values? Other than only needing 5 bytes total for each value instead of 7 bytes.
He HAS the baseline reference. His original code read one ADC value and sent it to the USB virtual com port. His issue is that the transfer rate was too slow. Hence all these messages about buffering data and sending to the USB in larger chunks. That *IS* the next step. Then worry about missing data samples due to polling delays. That is where interrupts or DMA comes in.
Hint about using DMA - configure the DMA for "circular" mode. You don't need any DMA interrupts, just let it keep filling and refilling your buffer. Your polling code looks for data in that buffer, extracts it, formats it as you like and adds it to your "pending USB data" buffer. Once your "pending USB data" buffer is full, send it. Then start filling it again from the DMA buffer.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2018-12-27 11:41 AM
I am using a STM32f072
the adc is configured as follow :
static void MX_ADC_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.LowPowerAutoPowerOff = DISABLE;
hadc.Init.ContinuousConvMode = ENABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
if (HAL_ADC_Init(&hadc) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
I know how to use DMA for the ADC, I know how to configure it as circular, I will try some polling as you suggest...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2018-12-27 11:53 AM
If you know how to use DMA circular mode with the ADC, the I would strongly suggest skipping the polling step (manually checking for ADC end-of-conversion then reading the data register) and go straight to the DMA configuration. You will need to end up using DMA or interrupts anyway to avoid polling delays possibly missing data. Using DMA, your "polling" then consists of checking to see if DMA has stored any new data in the circular buffer. The DMA will ensure you don't miss data samples (presuming your circular buffer is large enough).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2018-12-27 12:14 PM
I've tried this :
char buffer[64];
int ADC_buffer[1];
HAL_ADC_Start_DMA(&hadc, (uint32_t *)ADC_buffer, 1);
while (1)
{
snprintf( buffer, sizeof(buffer), "%6d\r", ADC_buffer[0] );
CDC_Transmit_FS((uint8_t*)buffer,7);
}
it works, but at the same speed as before (without DMA).