Hi Manitou,manitou wrote: ↑Mon Nov 02, 2015 12:28 amADC with DMA hack
OK, I finally got around to hacking adc.c to use DMA to read the ADC. As above we'll do 10,000 samples.
Not surprisingly, the 6475us is almost identical to the CONTINUOUS mode duration of 6478us -- the sampling rate of the ADC is the limiting factor. The ADC is in its default sampling configurartion: clockDIV2, and 15samples. Of course, the DMA implementation offers the opportunity to do other computing while the DMA is running, though additional functions would need to be defined for callback's or testing for DMA done.Code: Select all
>>> import pyb >>> import array >>> adc = pyb.ADC('X1') >>> buf = array.array('H', bytearray(20000)) >>> t1=pyb.micros(); n=adc.read_timed(buf,2000000); t2=pyb.micros() >>> t2-t1 6475
For my tests, I just added DMA init stuff to the adc_init_single() of adc.c, and then gutted (re-purposed) read_timed() to initiate a DMA on the ADC. Here are some snippets from the hack
Code: Select all
adcHandle->Init.ContinuousConvMode = ENABLE; // DMA adcHandle->Init.DMAContinuousRequests = ENABLE; // DMA ... // DMA init ADC1 is DMA2 channel0 stream 0 or 4 use DMA2_Stream0 thd // from dac.c __DMA2_CLK_ENABLE(); DMA_Handle.Instance = DMA2_Stream0; DMA_Handle.State = HAL_DMA_STATE_READY; HAL_DMA_DeInit(&DMA_Handle); DMA_Handle.Init.Channel = DMA_CHANNEL_0; // dac used 7 ? thd DMA_Handle.Init.Direction = DMA_PERIPH_TO_MEMORY; DMA_Handle.Init.PeriphInc = DMA_PINC_DISABLE; DMA_Handle.Init.MemInc = DMA_MINC_ENABLE; DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; DMA_Handle.Init.Mode = DMA_NORMAL; DMA_Handle.Init.Priority = DMA_PRIORITY_HIGH; DMA_Handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE; DMA_Handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL; DMA_Handle.Init.MemBurst = DMA_MBURST_SINGLE; // spi DMA_MBURST_INC4 ? DMA_Handle.Init.PeriphBurst = DMA_PBURST_SINGLE; HAL_DMA_Init(&DMA_Handle); __HAL_LINKDMA(adcHandle, DMA_Handle, DMA_Handle); .... HAL_ADC_Start_DMA(&self->handle, bufinfo.buf, nelems); // wait for DMA to complete: could use ISR/callback while (DMA_Handle.Instance->CR & DMA_SxCR_EN); // spin stream 0
thanks a lot for your code snippets!
I was able to integrate them with my copy of ADC.c in my clone of MicroPython 1.9.3... now I can call the read_timed method and the buffer is returned with samples inside!
For my work, I will be attempting to modify this further to transfer ADC samples with DMA only when an associated Timer ticks. I think this would consist of (2) method calls, one to get things started with
Code: Select all
HAL_ADC_Start_DMA
Code: Select all
HAL_ADC_Stop_DMA
Does anyone have any references I could use to base this work on? I am already reasonably understanding of the Timer peripherals, as I setup One-Pulse-Mode and timer master/slave setup for synchronizing several timers together.
Thanks again! I will post my code when I get somewhere interesting and relatively bug-free