This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

cc2650: Data transfer from Sensor Controller via DMA

Regards, Experts!

For best performance I need to implement data transfer from Sensor Controller to Cortex-M3 memory via DMA channel. I have found one suitable channel: UDMA_CHAN_AUX_SW.
How to handle this task? How to send "AUX Software event" from Sensor Controller? What Interrupt Vector Number for ISR-Handler I should implement when DMA finish one block transfer?

Thanks!
Andrei

  • Hi Andrei,

    I think a DMA transfer probably possible, but I don't know of an example that does this. Perhaps one of the examples in the Sensor Controller Studio has one that utilizes the DMA controller.

    I think you'd want to trigger the software event from the SC that wakes up the MCU domain to perform a DMA transfer. I'm not sure if you can use the AUX_SW uDMA channel or if you want the MCU to generate a software triggered DMA transfer. There might be some trade-offs when you put the MCU in a low power state while keeping the SC running.

    Let me see if I can find someone with more knowledge with the SC.

    Tom
  • Hi Tom!
    I just tested an app when Sensor Controller configure and start ADC with ADC_TRIGGER_AUX_TIMER0. ADC sampling period is 5us (200kHz).
    DMA channel UDMA_CHAN_AUX_ADC configured to PingPong mode at side of Cortex-M3. It works fine! Cortex-M3 is appears in the ISR-Handler (INT_AUX_ADC vector) only for reconfiguration of the PingPong structure.
    So, I intend to implement similar behavior via DMA channel UDMA_CHAN_AUX_SW. But unfortunately I did not find enough information in the technical documentation.
    Andrei
  • Where did you find this adc timer 0 example?

  • It is my own App. For now it is 1ch 200kHz data logger. Target App is 2ch 100kHz design.
  • Andrei that's great I have been getting some ok results with the GPtimer driver and the raw way of getting the adc to sample without the SCS stuff. I was unaware that you could do timer based sampling within SCS!  Is that app example something you are willing to share?

  • Program for Sensor Controller:

    adcEnableSync(ADC_REF_FIXED, ADC_SAMPLE_TIME_2P7_US, ADC_TRIGGER_MANUAL);
    adcFlushFifo();
    adcEnableSync(ADC_REF_FIXED, ADC_SAMPLE_TIME_2P7_US, ADC_TRIGGER_AUX_TIMER0);
    
    U16 n=0;
    adcSelectGpioInput(cfg.pAuxioASensorOutput[n]);
    n = 1 - n;
    
    adcStartAuxTimer0Trigger(5);
    
    while (state.exit == 0) {
    //    adcSelectGpioInput(cfg.pAuxioASensorOutput[n]);
        n = 1 - n;
    }
    
    adcStopAuxTimer0Trigger();
    adcDisable();
    
    

    Program for Cortex-M3:

    static void dma_config(void)
    {
        /* Config here dmaControlTableEntry and dmaControlTableEntry_Alt for Ping-Pong operation. */
    }
    
    static void adc_Isr(UArg arg)
    {
        /* Reconfig dmaControlTableEntry or dmaControlTableEntry_Alt for next loop. */
    }
    
    static void dma_open(void)
    {
        if (!Power_setDependency(PERIPH_UDMA)) while(1);
    
        /* Select the primary data structures. */
        HWREG(UDMA0_BASE + UDMA_O_CLEARCHNLPRIALT) = (1<<UDMA_CHAN_AUX_ADC);
        /* Set Channel Enable. */
        HWREG(UDMA0_BASE + UDMA_O_SETCHANNELEN) = (1<<UDMA_CHAN_AUX_ADC);
    
        /* Disable, configure and enable DMA channel. */
        HWREG(AUX_EVCTL_BASE + AUX_EVCTL_O_DMACTL) &= ~(AUX_EVCTL_DMACTL_EN);
        HWREG(AUX_EVCTL_BASE + AUX_EVCTL_O_DMACTL) = (AUX_EVCTL_DMACTL_SEL_FIFO_NOT_EMPTY |
                                                      AUX_EVCTL_DMACTL_REQ_MODE_SINGLE);
        HWREG(AUX_EVCTL_BASE + AUX_EVCTL_O_DMACTL) = (AUX_EVCTL_DMACTL_SEL_FIFO_NOT_EMPTY |
                                                      AUX_EVCTL_DMACTL_REQ_MODE_SINGLE    |
                                                      AUX_EVCTL_DMACTL_EN);
    }
    
    static void sc_open(void)
    {
        // Initialize the Sensor Controller
        scifOsalInit();
        scifOsalRegisterCtrlReadyCallback(scCtrlReadyCallback);
        scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
        scifInit(&scifDriverSetup);
    
        /* Reset Sensor Controller Task. */
        scifResetTaskStructs(BV(SCIF_ADC_DATA_LOGGER_TASK_ID), BV(SCIF_STRUCT_CFG));
    
        /* Start Sensor Controller Task. */
        scifExecuteTasksOnceNbl(BV(SCIF_ADC_DATA_LOGGER_TASK_ID));
    }
    
    void adc_open(void)
    {
        Hwi_Params hwiParams;
    
        Power_setConstraint(Power_SB_DISALLOW);
    
        // Setup HWI handler
        Hwi_Params_init(&hwiParams);
        Hwi_construct(&hwiStruct, INT_AUX_ADC, adc_Isr, &hwiParams, NULL);
    
        dma_config();
        dma_open();
        sc_open();
    }
    

  • Hi Tom!

    Do you have any news on my task? Is it possible to transfer data from SC via DMA channel UDMA_CHAN_AUX_SW?
  • Hi Andrei,
    Please can you provide me a Program for Sensor Controller and main.c file of Cortex-M3.
  • Hi Pavan!

    My program is already at e2e: http://e2e.ti.com/support/wireless_connectivity/bluetooth_low_energy/f/538/p/532628/1944175#1944175

    This is 1-channel 200kHz case. You just have to expand two functions for your purpose. The first function is dma_config() and the second is adc_Isr(). Then call adc_open() from main.c

    Example of dma_config() and adc_Isr() from my own project:

    static inline void adc_iter(uint32_t udma_mode)
    {
        volatile tDMAControlTable *dmaControlTableEntry;
        uint32_t index = adc_index;
        uint16_t* addr = adc_buff[index];
    
        adc_index = (++index < ADC_BUFF_NUM) ? index : 0;
        index &= 1;
    
        /* Setup RX side */
        dmaControlTableEntry = (index ? &dmaAdcControlTableEntry : &dmaAdcControlTableEntry_alt);
        dmaControlTableEntry->ui32Control  = udma_mode | UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1;
        dmaControlTableEntry->pvSrcEndAddr = (void *)(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCFIFO);
        dmaControlTableEntry->pvDstEndAddr = (void *)((uint32_t)addr + (ADC_BUFF_LEN << 1) - 1);
        dmaControlTableEntry->ui32Control |= UDMACC26XX_SET_TRANSFER_SIZE(ADC_BUFF_LEN);
    }
    
    static void dma_config(void)
    {
        adc_index = 0;
        adc_iter(UDMA_MODE_PINGPONG);
        adc_iter(UDMA_MODE_PINGPONG);
    }
    
    static void adc_Isr(UArg arg)
    {
        /* Determine if the DMA channel has completed (UDMACC26XX_channelDone) */
        if (HWREG(UDMA0_BASE + UDMA_O_REQDONE) & (1<<UDMA_CHAN_AUX_ADC))
        {
            adc_iter(UDMA_MODE_PINGPONG);
    
            /* clear DMA done interrupt (UDMACC26XX_clearInterrupt) */
            HWREG(UDMA0_BASE + UDMA_O_REQDONE) = (1<<UDMA_CHAN_AUX_ADC);
        }
    
        // Clear ADC_IRQ flag. Note: Missing driver for this.
        HWREGBITW(AUX_EVCTL_BASE + AUX_EVCTL_O_EVTOMCUFLAGSCLR, AUX_EVCTL_EVTOMCUFLAGSCLR_ADC_IRQ_BITN) = 1;
    }
    

    BR!

    Andrei