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.

TMS570LC4357: ADC with DMA and no interrupts

Part Number: TMS570LC4357
Other Parts Discussed in Thread: HALCOGEN

Tool/software:

I am attempting to utilize DMA with the ADC1 of the TMS570LC4357 without any interrupts. My goal is to sample the ADC at a rate configured by the RTI which I have configured to be the hardware trigger to the ADC. Once the ADC conversion is complete (for 2 channels in a single group) it should trigger the DMA to do a transfer that simply copies the new ADC conversion results to a buffer that has been configured to be shared in HalCoGen and the linker file. 

I have attached the adc.c and main.c files for this. My later goal (commented out code) is to chain the DMA to a second transfer so I can keep track of the number of DMA transfers that have occurred since my last check of it. 

After all this the DMA is not triggering transfers, and it's seeming like the ADC is not successfully converting any results. Any guidance or suggestions?

/** @file HL_adc.c 
*   @brief ADC Driver Source File
*   @date 11-Dec-2018
*   @version 04.07.01
*
*   This file contains:
*   - API Functions
*   - Interrupt Handlers
*   .
*   which are relevant for the ADC driver.
*/

/* 
* Copyright (C) 2009-2018 Texas Instruments Incorporated - www.ti.com  
* 
* 
*  Redistribution and use in source and binary forms, with or without 
*  modification, are permitted provided that the following conditions 
*  are met:
*
*    Redistributions of source code must retain the above copyright 
*    notice, this list of conditions and the following disclaimer.
*
*    Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the 
*    documentation and/or other materials provided with the   
*    distribution.
*
*    Neither the name of Texas Instruments Incorporated nor the names of
*    its contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
*  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/


/* USER CODE BEGIN (0) */
/* USER CODE END */

/* Include Files */

#include "HL_adc.h"
#include "HL_sys_vim.h"

/* USER CODE BEGIN (1) */
/* USER CODE END */

/** @fn void adcInit(void)
*   @brief Initializes ADC Driver
*
*   This function initializes the ADC driver.
*
*/
/* USER CODE BEGIN (2) */
/* USER CODE END */
/* SourceId : ADC_SourceId_001 */
/* DesignId : ADC_DesignId_001 */
/* Requirements : HL_CONQ_ADC_SR2 */
void adcInit(void)
{
/* USER CODE BEGIN (3) */
/* USER CODE END */

    /** @b Initialize @b ADC1: */

    /** - Reset ADC module */
    adcREG1->RSTCR = 1U;
    adcREG1->RSTCR = 0U;

    /** - Enable 12-BIT ADC  */
    adcREG1->OPMODECR |= 0x80000000U;
	
    /** - Setup prescaler */
    adcREG1->CLOCKCR = 9U;
 
    /** - Setup memory boundaries */
    adcREG1->BNDCR  = (uint32)((uint32)8U << 16U) | (8U + 8U);
    adcREG1->BNDEND = (adcREG1->BNDEND & 0xFFFF0000U) | (2U);
 
    /** - Setup event group conversion mode
    *     - Setup data format
    *     - Enable/Disable channel id in conversion result
    *     - Enable/Disable continuous conversion
    */
    adcREG1->GxMODECR[0U] = (uint32)ADC_12_BIT
                          | (uint32)0x00000000U
                          | (uint32)0x00000000U;

    /** - Setup event group hardware trigger
     *     - Setup hardware trigger edge
     *     - Setup hardware trigger source
     */
    adcREG1->EVSRC = (uint32)0x00000008U
                   | (uint32)ADC1_RTI_COMP0;

    /** - Setup event group sample window */
    adcREG1->EVSAMP = 10U;

    /** - Setup event group sample discharge 
    *     - Setup discharge prescaler
    *     - Enable/Disable discharge
    */
    adcREG1->EVSAMPDISEN = (uint32)((uint32)1U << 8U)
                         | (uint32)0x00000001U;

    /** - Setup group 1 conversion mode
    *     - Setup data format
    *     - Enable/Disable channel id in conversion result
    *     - Enable/Disable continuous conversion
    */
    adcREG1->GxMODECR[1U] = (uint32)ADC_12_BIT
                          | (uint32)0x00000000U
                          | (uint32)0x00000000U
                          | (uint32)0x00000000U;

    /** - Setup group 1 hardware trigger
     *     - Setup hardware trigger edge
     *     - Setup hardware trigger source
     */
    adcREG1->G1SRC = (uint32)0x00000008U
                   | (uint32)ADC1_RTI_COMP0;

    /** - Setup group 1 sample window */
    adcREG1->G1SAMP = 10U;

    /** - Setup group 1 sample discharge 
    *     - Setup discharge prescaler
    *     - Enable/Disable discharge
    */
    adcREG1->G1SAMPDISEN = (uint32)((uint32)0U << 8U)
                         | (uint32)0x00000000U;

    /** - Setup group 2 conversion mode
     *     - Setup data format
     *     - Enable/Disable channel id in conversion result
     *     - Enable/Disable continuous conversion
     */
    adcREG1->GxMODECR[2U] = (uint32)ADC_12_BIT
                          | (uint32)0x00000000U
                          | (uint32)0x00000000U
                          | (uint32)0x00000000U;

    /** - Setup group 2 hardware trigger
	*     - Setup hardware trigger edge
    *     - Setup hardware trigger source
	*/
    adcREG1->G2SRC = (uint32)0x00000000U
                   | (uint32)ADC1_EVENT;

    /** - Setup group 2 sample window */
    adcREG1->G2SAMP = 1U;

    /** - Setup group 2 sample discharge 
    *     - Setup discharge prescaler
    *     - Enable/Disable discharge
    */
    adcREG1->G2SAMPDISEN = (uint32)((uint32)0U << 8U)
                         | (uint32)0x00000000U;

    /** - ADC1 EVT pin output value */
    adcREG1->EVTOUT = 0U;

    /** - ADC1 EVT pin direction */
    adcREG1->EVTDIR = 0U;
	
    /** - ADC1 EVT pin open drain enable */
	adcREG1->EVTPDR = 0U;

    /** - ADC1 EVT pin pullup / pulldown selection */
	adcREG1->EVTPSEL = 1U;

    /** - ADC1 EVT pin pullup / pulldown enable*/
	adcREG1->EVTDIS = 0U;
	
	/** - Enable ADC module */
    adcREG1->OPMODECR |= 0x80140001U;
	
    /** - Wait for buffer initialization complete */
    /*SAFETYMCUSW 28 D MR:NA <APPROVED> "Hardware status bit read check" */
    while (((adcREG1->BNDEND & 0xFFFF0000U) >> 16U ) != 0U) 
    { 
	} /* Wait */
    
    /** - Setup parity */
    adcREG1->PARCR = 0x00000005U;


/* USER CODE BEGIN (4) */
/* USER CODE END */
}

/* USER CODE BEGIN (5) */
/* USER CODE END */


/** - s_adcSelect is used as constant table for channel selection */
static const uint32 s_adcSelect[2U][3U] =
{
    {0x00000001U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00010000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U,
    0x00000000U |
    0x00000002U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00020000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U,
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U},
    {0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U,
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U,
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U |
    0x00000000U,}
};

/** - s_adcFiFoSize is used as constant table for channel selection */
static const uint32 s_adcFiFoSize[2U][3U] =
{
    {2U,
    2U,
    16U},
    {16U,
    16U,
    16U}
};

/* USER CODE BEGIN (6) */
/* USER CODE END */

/** @fn void adcStartConversion(adcBASE_t *adc, uint32 group)
*   @brief Starts an ADC conversion
*   @param[in] adc Pointer to ADC module:
*              - adcREG1: ADC1 module pointer
*              - adcREG2: ADC2 module pointer
*   @param[in] group Hardware group of ADC module:
*              - adcGROUP0: ADC event group
*              - adcGROUP1: ADC group 1
*              - adcGROUP2: ADC group 2
*
*   This function starts a conversion of the ADC hardware group.
*
*/
/* SourceId : ADC_SourceId_002 */
/* DesignId : ADC_DesignId_002 */
/* Requirements : HL_CONQ_ADC_SR3 */
void adcStartConversion(adcBASE_t *adc, uint32 group)
{
    uint32 index = (adc == adcREG1) ? 0U : 1U;

/* USER CODE BEGIN (7) */
/* USER CODE END */

    /** - Setup FiFo size */
    adc->GxINTCR[group] = s_adcFiFoSize[index][group];

    /** - Start Conversion */
    adc->GxSEL[group] = s_adcSelect[index][group];

    /**   @note The function adcInit has to be called before this function can be used. */

/* USER CODE BEGIN (8) */
/* USER CODE END */
}

/* USER CODE BEGIN (9) */
/* USER CODE END */


/** @fn void adcStopConversion(adcBASE_t *adc, uint32 group)
*   @brief Stops an ADC conversion
*   @param[in] adc Pointer to ADC module:
*              - adcREG1: ADC1 module pointer
*              - adcREG2: ADC2 module pointer
*   @param[in] group Hardware group of ADC module:
*              - adcGROUP0: ADC event group
*              - adcGROUP1: ADC group 1
*              - adcGROUP2: ADC group 2
*
*   This function stops a conversion of the ADC hardware group.
*
*/
/* SourceId : ADC_SourceId_003 */
/* DesignId : ADC_DesignId_003 */
/* Requirements : HL_CONQ_ADC_SR4 */
void adcStopConversion(adcBASE_t *adc, uint32 group)
{
/* USER CODE BEGIN (10) */
/* USER CODE END */

    /** - Stop Conversion */
    adc->GxSEL[group] = 0U;

    /**   @note The function adcInit has to be called before this function can be used. */

/* USER CODE BEGIN (11) */
/* USER CODE END */
}

/* USER CODE BEGIN (12) */
/* USER CODE END */


/** @fn void adcResetFiFo(adcBASE_t *adc, uint32 group)
*   @brief Resets FiFo read and write pointer.
*   @param[in] adc Pointer to ADC module:
*              - adcREG1: ADC1 module pointer
*              - adcREG2: ADC2 module pointer
*   @param[in] group Hardware group of ADC module:
*              - adcGROUP0: ADC event group
*              - adcGROUP1: ADC group 1
*              - adcGROUP2: ADC group 2
*
*   This function resets the FiFo read and write pointers.
*
*/
/* SourceId : ADC_SourceId_004 */
/* DesignId : ADC_DesignId_004 */
/* Requirements : HL_CONQ_ADC_SR5 */
void adcResetFiFo(adcBASE_t *adc, uint32 group)
{
/* USER CODE BEGIN (13) */
/* USER CODE END */

    /** - Reset FiFo */
    adc->GxFIFORESETCR[group] = 1U;

    /**   @note The function adcInit has to be called before this function can be used.\n
    *           the conversion should be stopped before calling this function. 
    */

/* USER CODE BEGIN (14) */
/* USER CODE END */
}

/* USER CODE BEGIN (15) */
/* USER CODE END */


/** @fn uint32 adcGetData(adcBASE_t *adc, uint32 group, adcData_t * data)
*   @brief Gets converted a ADC values
*   @param[in] adc Pointer to ADC module:
*              - adcREG1: ADC1 module pointer
*              - adcREG2: ADC2 module pointer
*   @param[in] group Hardware group of ADC module:
*              - adcGROUP0: ADC event group
*              - adcGROUP1: ADC group 1
*              - adcGROUP2: ADC group 2
*   @param[out] data Pointer to store ADC converted data
*   @return The function will return the number of converted values copied into data buffer:
*
*   This function writes a ADC message into a ADC message box.
*
*/
/* SourceId : ADC_SourceId_005 */
/* DesignId : ADC_DesignId_005 */
/* Requirements : HL_CONQ_ADC_SR6 */
uint32 adcGetData(adcBASE_t *adc, uint32 group, adcData_t * data)
{
    uint32  i;
    uint32  buf;
    uint32  mode;    
    uint32  index = (adc == adcREG1) ? 0U : 1U;
	
	uint32  intcr_reg = adc->GxINTCR[group];
    uint32  count = (intcr_reg >= 256U) ? s_adcFiFoSize[index][group] : (s_adcFiFoSize[index][group] - (uint32)(intcr_reg & 0xFFU));
    adcData_t *ptr = data; 

/* USER CODE BEGIN (16) */
/* USER CODE END */

    mode = (adc->OPMODECR & ADC_12_BIT_MODE);

    if(mode == ADC_12_BIT_MODE)
      {
        /** -  Get conversion data and channel/pin id */
        for (i = 0U; i < count; i++)
        {
          buf        = adc->GxBUF[group].BUF0;
		  /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
          ptr->value = (uint16)(buf & 0xFFFU);
          ptr->id    = (uint32)((buf >> 16U) & 0x1FU);
          /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */
		  ptr++;
        }
      }
      else
      {
        /** -  Get conversion data and channel/pin id */
        for (i = 0U; i < count; i++)
        {
          buf        = adc->GxBUF[group].BUF0;
		  /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
          ptr->value = (uint16)(buf & 0x3FFU);
          ptr->id    = (uint32)((buf >> 10U) & 0x1FU);
          /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */
		  ptr++;
        }
      }


    adc->GxINTFLG[group] = 9U;

    /**   @note The function adcInit has to be called before this function can be used.\n
    *           The user is responsible to initialize the message box.
    */

/* USER CODE BEGIN (17) */
/* USER CODE END */

    return count;
}

/* USER CODE BEGIN (18) */
/* USER CODE END */


/** @fn uint32 adcIsFifoFull(adcBASE_t *adc, uint32 group)
*   @brief Checks if FiFo buffer is full
*   @param[in] adc Pointer to ADC module:
*              - adcREG1: ADC1 module pointer
*              - adcREG2: ADC2 module pointer
*   @param[in] group Hardware group of ADC module:
*              - adcGROUP0: ADC event group
*              - adcGROUP1: ADC group 1
*              - adcGROUP2: ADC group 2
*   @return The function will return:
*           - 0: When FiFo buffer is not full   
*           - 1: When FiFo buffer is full   
*           - 3: When FiFo buffer overflow occurred    
*
*   This function checks FiFo buffer status.
*
*/
/* SourceId : ADC_SourceId_006 */
/* DesignId : ADC_DesignId_006 */
/* Requirements : HL_CONQ_ADC_SR7 */
uint32 adcIsFifoFull(adcBASE_t *adc, uint32 group)
{
    uint32 flags;

/* USER CODE BEGIN (19) */
/* USER CODE END */

    /** - Read FiFo flags */
    flags = adc->GxINTFLG[group] & 3U;

    /**   @note The function adcInit has to be called before this function can be used. */

/* USER CODE BEGIN (20) */
/* USER CODE END */

    return flags;
}

/* USER CODE BEGIN (21) */
/* USER CODE END */


/** @fn uint32 adcIsConversionComplete(adcBASE_t *adc, uint32 group)
*   @brief Checks if Conversion is complete
*   @param[in] adc Pointer to ADC module:
*              - adcREG1: ADC1 module pointer
*              - adcREG2: ADC2 module pointer
*   @param[in] group Hardware group of ADC module:
*              - adcGROUP0: ADC event group
*              - adcGROUP1: ADC group 1
*              - adcGROUP2: ADC group 2
*   @return The function will return:
*           - 0: When is not finished   
*           - 8: When conversion is complete   
*
*   This function checks if conversion is complete.
*
*/
/* SourceId : ADC_SourceId_007 */
/* DesignId : ADC_DesignId_007 */
/* Requirements : HL_CONQ_ADC_SR8 */
uint32 adcIsConversionComplete(adcBASE_t *adc, uint32 group)
{
    uint32 flags;

/* USER CODE BEGIN (22) */
/* USER CODE END */

    /** - Read conversion flags */
    flags = adc->GxINTFLG[group] & 8U;

    /**   @note The function adcInit has to be called before this function can be used. */

/* USER CODE BEGIN (23) */
/* USER CODE END */

    return flags;
}

/* USER CODE BEGIN (24) */
/* USER CODE END */

/** @fn void adcCalibration(adcBASE_t *adc)
*   @brief Computes offset error using Calibration mode
*   @param[in] adc Pointer to ADC module:
*              - adcREG1: ADC1 module pointer
*              - adcREG2: ADC2 module pointer
*   This function computes offset error using Calibration mode
*
*/
/* SourceId : ADC_SourceId_008 */
/* DesignId : ADC_DesignId_010 */
/* Requirements : HL_CONQ_ADC_SR11 */
void adcCalibration(adcBASE_t *adc)
{
/* USER CODE BEGIN (25) */
/* USER CODE END */
    
	uint32 conv_val[5U]={0U,0U,0U,0U,0U};
	uint32 loop_index=0U;
	uint32 offset_error=0U;
	uint32 backup_mode;
	
	/** - Backup Mode before Calibration  */
	backup_mode = adc->OPMODECR;
	
	/** - Enable 12-BIT ADC  */
	adc->OPMODECR |= 0x80000000U;

	/* Disable all channels for conversion */
	adc->GxSEL[0U]=0x00U;
	adc->GxSEL[1U]=0x00U;
	adc->GxSEL[2U]=0x00U;

	for(loop_index=0U;loop_index<4U;loop_index++)
	{
		/* Disable Self Test and Calibration mode */
		adc->CALCR=0x0U;
	
		switch(loop_index)
		{
			case 0U : 	/* Test 1 : Bride En = 0 , HiLo =0 */
						adc->CALCR=0x0U;
						break;

			case 1U :	/* Test 1 : Bride En = 0 , HiLo =1 */
						adc->CALCR=0x0100U;
						break;

			case 2U : 	/* Test 1 : Bride En = 1 , HiLo =0 */
						adc->CALCR=0x0200U;
						break;
		
			case 3U : 	/* Test 1 : Bride En = 1 , HiLo =1 */
						adc->CALCR=0x0300U;
						break;
			default :
			            break;
		}
	
		/* Enable Calibration mode */
		adc->CALCR|=0x1U;
	
		/* Start calibration conversion */
		adc->CALCR|=0x00010000U;

		/* Wait for calibration conversion to complete */
		/*SAFETYMCUSW 28 D MR:NA <APPROVED> "Hardware status bit read check" */
		while((adc->CALCR & 0x00010000U)==0x00010000U)
	    { 
	    } /* Wait */

		/* Read converted value */
		conv_val[loop_index]= adc->CALR;
	}

	/* Disable Self Test and Calibration mode */
	adc->CALCR=0x0U;

	/* Compute the Offset error correction value */
	conv_val[4U]=conv_val[0U]+ conv_val[1U] + conv_val[2U] + conv_val[3U];

	conv_val[4U]=(conv_val[4U]/4U);

	offset_error=conv_val[4U]-0x7FFU;

	/*Write the offset error to the Calibration register */
	/* Load 2;s complement of the computed value to ADCALR register */
	offset_error=~offset_error;
	offset_error=offset_error & 0xFFFU;
	offset_error=offset_error+1U;

	adc->CALR = offset_error;

  /** - Restore Mode after Calibration  */
	adc->OPMODECR = backup_mode;
	
 /**   @note The function adcInit has to be called before using this function. */

/* USER CODE BEGIN (26) */
/* USER CODE END */
}


/** @fn void adcMidPointCalibration(adcBASE_t *adc)
*   @brief Computes offset error using Mid Point Calibration mode
*   @param[in] adc Pointer to ADC module:
*              - adcREG1: ADC1 module pointer
*              - adcREG2: ADC2 module pointer
*	@return This function will return offset error using Mid Point Calibration mode
*
*   This function computes offset error using Mid Point Calibration mode
*
*/
/* SourceId : ADC_SourceId_009 */
/* DesignId : ADC_DesignId_011 */
/* Requirements : HL_CONQ_ADC_SR12 */
uint32 adcMidPointCalibration(adcBASE_t *adc)
{
/* USER CODE BEGIN (27) */
/* USER CODE END */
    
	uint32 conv_val[3U]={0U,0U,0U};
	uint32 loop_index=0U;
	uint32 offset_error=0U;
	uint32 backup_mode;
	
	/** - Backup Mode before Calibration  */
	backup_mode = adc->OPMODECR;
	
	/** - Enable 12-BIT ADC  */
	adc->OPMODECR |= 0x80000000U;

	/* Disable all channels for conversion */
	adc->GxSEL[0U]=0x00U;
	adc->GxSEL[1U]=0x00U;
	adc->GxSEL[2U]=0x00U;

	for(loop_index=0U;loop_index<2U;loop_index++)
	{
		/* Disable Self Test and Calibration mode */
		adc->CALCR=0x0U;
	
		switch(loop_index)
		{
			case 0U : 	/* Test 1 : Bride En = 0 , HiLo =0 */
						adc->CALCR=0x0U;
						break;

			case 1U :	/* Test 1 : Bride En = 0 , HiLo =1 */
						adc->CALCR=0x0100U;
						break;

			default :
			            break;						

		}
	
		/* Enable Calibration mode */
		adc->CALCR|=0x1U;
	
		/* Start calibration conversion */
		adc->CALCR|=0x00010000U;

		/* Wait for calibration conversion to complete */
		/*SAFETYMCUSW 28 D MR:NA <APPROVED> "Hardware status bit read check" */
		while((adc->CALCR & 0x00010000U)==0x00010000U)
	    { 
	    } /* Wait */

		/* Read converted value */
		conv_val[loop_index]= adc->CALR;
	}

	/* Disable Self Test and Calibration mode */
	adc->CALCR=0x0U;

	/* Compute the Offset error correction value */
	conv_val[2U]=(conv_val[0U])+ (conv_val[1U]);

	conv_val[2U]=(conv_val[2U]/2U);

	offset_error=conv_val[2U]-0x7FFU;

	/* Write the offset error to the Calibration register           */
	/* Load 2's complement of the computed value to ADCALR register */
	offset_error=~offset_error;
	offset_error=offset_error+1U;
	offset_error=offset_error & 0xFFFU;

	adc->CALR = offset_error;

  /** - Restore Mode after Calibration  */
	adc->OPMODECR = backup_mode;
	
	return(offset_error);

 /**   @note The function adcInit has to be called before this function can be used. */

/* USER CODE BEGIN (28) */
/* USER CODE END */
}

/* USER CODE BEGIN (29) */
/* USER CODE END */

/** @fn void adcEnableNotification(adcBASE_t *adc, uint32 group)
*   @brief Enable notification
*   @param[in] adc Pointer to ADC module:
*              - adcREG1: ADC1 module pointer
*              - adcREG2: ADC2 module pointer
*   @param[in] group Hardware group of ADC module:
*              - adcGROUP0: ADC event group
*              - adcGROUP1: ADC group 1
*              - adcGROUP2: ADC group 2
*
*   This function will enable the notification of a conversion.
*   In single conversion mode for conversion complete and
*   in continuous conversion mode when the FiFo buffer is full.
*
*/
/* SourceId : ADC_SourceId_010 */
/* DesignId : ADC_DesignId_008 */
/* Requirements : HL_CONQ_ADC_SR9 */
void adcEnableNotification(adcBASE_t *adc, uint32 group)
{
    uint32 notif = (((uint32)(adc->GxMODECR[group]) & 2U) == 2U) ? 1U : 8U;

/* USER CODE BEGIN (30) */
/* USER CODE END */

    adc->GxINTENA[group] = notif;

    /**   @note The function adcInit has to be called before this function can be used.\n
    *           This function should be called before the conversion is started
    */

/* USER CODE BEGIN (31) */
/* USER CODE END */
}

/* USER CODE BEGIN (32) */
/* USER CODE END */


/** @fn void adcDisableNotification(adcBASE_t *adc, uint32 group)
*   @brief Disable notification
*   @param[in] adc Pointer to ADC module:
*              - adcREG1: ADC1 module pointer
*              - adcREG2: ADC2 module pointer
*   @param[in] group Hardware group of ADC module:
*              - adcGROUP0: ADC event group
*              - adcGROUP1: ADC group 1
*              - adcGROUP2: ADC group 2
*
*   This function will disable the notification of a conversion.
*/
/* SourceId : ADC_SourceId_011 */
/* DesignId : ADC_DesignId_008 */
/* Requirements : HL_CONQ_ADC_SR9 */
void adcDisableNotification(adcBASE_t *adc, uint32 group)
{
/* USER CODE BEGIN (33) */
/* USER CODE END */

    adc->GxINTENA[group] = 0U;

    /**   @note The function adcInit has to be called before this function can be used. */

/* USER CODE BEGIN (34) */
/* USER CODE END */
}

/** @fn void adcSetEVTPin(adcBASE_t *adc, uint32 value)
*   @brief Set ADCEVT pin
*   @param[in] adc Pointer to ADC module:
*              - adcREG1: ADC1 module pointer
*   @param[in] value Value to be set: 0 or 1
*
*   This function will set the ADC EVT pin if configured as an output pin.
*/
/* SourceId : ADC_SourceId_012 */
/* DesignId : ADC_DesignId_014 */
/* Requirements : HL_CONQ_ADC_SR13 */
void adcSetEVTPin(adcBASE_t *adc, uint32 value)
{
    adc->EVTOUT = value;
}

/** @fn uint32 adcGetEVTPin(adcBASE_t *adc)
*   @brief Set ADCEVT pin
*   @param[in] adc Pointer to ADC module:
*              - adcREG1: ADC1 module pointer
*   @return Value of the ADC EVT pin: 0 or 1
*
*   This function will return the value of ADC EVT pin.
*/
/* SourceId : ADC_SourceId_013 */
/* DesignId : ADC_DesignId_015 */
/* Requirements : HL_CONQ_ADC_SR14 */
uint32 adcGetEVTPin(adcBASE_t *adc)
{
    return adc->EVTIN;
}

/** @fn void adc1GetConfigValue(adc_config_reg_t *config_reg, config_value_type_t type)
*   @brief Get the initial or current values of the configuration registers
*
*	@param[in] *config_reg: pointer to the struct to which the initial or current 
*                           value of the configuration registers need to be stored
*	@param[in] type: 	whether initial or current value of the configuration registers need to be stored
*						- InitialValue: initial value of the configuration registers will be stored 
*                                       in the struct pointed by config_reg
*						- CurrentValue: initial value of the configuration registers will be stored 
*                                       in the struct pointed by config_reg
*
*   This function will copy the initial or current value (depending on the parameter 'type') 
*   of the configuration registers to the struct pointed by config_reg
*
*/
/* SourceId : ADC_SourceId_014 */
/* DesignId : ADC_DesignId_012 */
/* Requirements : HL_CONQ_ADC_SR15 */
void adc1GetConfigValue(adc_config_reg_t *config_reg, config_value_type_t type)
{
	if (type == InitialValue)
	{
        config_reg->CONFIG_OPMODECR = ADC1_OPMODECR_CONFIGVALUE;
        config_reg->CONFIG_CLOCKCR = ADC1_CLOCKCR_CONFIGVALUE;
        config_reg->CONFIG_GxMODECR[0U] = ADC1_G0MODECR_CONFIGVALUE;
        config_reg->CONFIG_GxMODECR[1U] = ADC1_G1MODECR_CONFIGVALUE;
        config_reg->CONFIG_GxMODECR[2U] = ADC1_G2MODECR_CONFIGVALUE;
        config_reg->CONFIG_G0SRC = ADC1_G0SRC_CONFIGVALUE;
        config_reg->CONFIG_G1SRC = ADC1_G1SRC_CONFIGVALUE;
        config_reg->CONFIG_G2SRC = ADC1_G2SRC_CONFIGVALUE;
        config_reg->CONFIG_BNDCR = ADC1_BNDCR_CONFIGVALUE;
        config_reg->CONFIG_BNDEND = ADC1_BNDEND_CONFIGVALUE;
        config_reg->CONFIG_G0SAMP = ADC1_G0SAMP_CONFIGVALUE;
        config_reg->CONFIG_G1SAMP = ADC1_G1SAMP_CONFIGVALUE;
        config_reg->CONFIG_G2SAMP = ADC1_G2SAMP_CONFIGVALUE;
        config_reg->CONFIG_G0SAMPDISEN = ADC1_G0SAMPDISEN_CONFIGVALUE;
        config_reg->CONFIG_G1SAMPDISEN = ADC1_G1SAMPDISEN_CONFIGVALUE;
        config_reg->CONFIG_G2SAMPDISEN = ADC1_G2SAMPDISEN_CONFIGVALUE;
        config_reg->CONFIG_PARCR = ADC1_PARCR_CONFIGVALUE;
	}
	else
	{
        config_reg->CONFIG_OPMODECR = adcREG1->OPMODECR;
        config_reg->CONFIG_CLOCKCR = adcREG1->CLOCKCR;
        config_reg->CONFIG_GxMODECR[0U] = adcREG1->GxMODECR[0U];
        config_reg->CONFIG_GxMODECR[1U] = adcREG1->GxMODECR[1U];
        config_reg->CONFIG_GxMODECR[2U] = adcREG1->GxMODECR[2U];
        config_reg->CONFIG_G0SRC = adcREG1->EVSRC;
        config_reg->CONFIG_G1SRC = adcREG1->G1SRC;
        config_reg->CONFIG_G2SRC = adcREG1->G2SRC;
        config_reg->CONFIG_BNDCR = adcREG1->BNDCR;
        config_reg->CONFIG_BNDEND = adcREG1->BNDEND;
        config_reg->CONFIG_G0SAMP = adcREG1->EVSAMP;
        config_reg->CONFIG_G1SAMP = adcREG1->G1SAMP;
        config_reg->CONFIG_G2SAMP = adcREG1->G2SAMP;
        config_reg->CONFIG_G0SAMPDISEN = adcREG1->EVSAMPDISEN;
        config_reg->CONFIG_G1SAMPDISEN = adcREG1->G1SAMPDISEN;
        config_reg->CONFIG_G2SAMPDISEN = adcREG1->G2SAMPDISEN;
        config_reg->CONFIG_PARCR = adcREG1->PARCR;
	}
}


/* USER CODE BEGIN (35) */
/* USER CODE END */






/** @file HL_sys_main.c 
*   @brief Application main file
*   @date 11-Dec-2018
*   @version 04.07.01
*
*   This file contains an empty main function,
*   which can be used for the application.
*/

/* 
* Copyright (C) 2009-2018 Texas Instruments Incorporated - www.ti.com  
* 
* 
*  Redistribution and use in source and binary forms, with or without 
*  modification, are permitted provided that the following conditions 
*  are met:
*
*    Redistributions of source code must retain the above copyright 
*    notice, this list of conditions and the following disclaimer.
*
*    Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the 
*    documentation and/or other materials provided with the   
*    distribution.
*
*    Neither the name of Texas Instruments Incorporated nor the names of
*    its contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
*  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/


/* USER CODE BEGIN (0) */
/* USER CODE END */

/* Include Files */

#include "HL_sys_common.h"

/* USER CODE BEGIN (1) */
#include "HL_adc.h"
#include "HL_sys_dma.h"
#include "HL_rti.h"

#define RAW_SIZE 256U
#define MAX_DMA_TRANSFER_CNT 128U

#define ADC1_GE_DMA_REQ DMA_REQ7
#define ADC1_GE_DMA_CHAN DMA_CH3

// DMA transfer count tracker -- these request lines are HET and MIBSPI4/5
#define ADC1_GE_COUNT_DMA_REQ DMA_REQ24
#define ADC1_GE_COUNT_DMA_CHAN DMA_CH24

/**
 *  @brief Circular buffer for DMA sampling
 */
typedef struct SampleCircBuf_t
{
    volatile uint32_t bufferRawADC[RAW_SIZE];
    volatile uint8_t writePtr;
    uint8_t head;
} SampleCircBuf_t;

static const dmaRequest_t dmaReqlineAdcGE = ADC1_GE_DMA_REQ;
static const dmaRequest_t dmaReqlineAdcGECount = ADC1_GE_COUNT_DMA_REQ;
static const dmaChannel_t adcGEDmaChan = ADC1_GE_DMA_CHAN;
static const dmaChannel_t adcGECountDmaChan = ADC1_GE_COUNT_DMA_CHAN;

static g_dmaCTRL adcGEDmaCtrl;
static g_dmaCTRL adcGECountDmaCtrl;

#pragma SET_DATA_SECTION(".sharedRAM")
// Each index is a count, assume when the pointer to this is incremented by DMA that 2 conversions took place
static const uint8_t dmaWriteCnt[MAX_DMA_TRANSFER_CNT] = {
    0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
    32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
    64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94,
    96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126,
    128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158,
    160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190,
    192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222,
    224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 254
};
static SampleCircBuf_t adcSampleBuffers[2U];

#pragma SET_DATA_SECTION()


static void configureAdcDma(void);
/* USER CODE END */

/** @fn void main(void)
*   @brief Application main function
*   @note This function is empty by default.
*
*   This function is called after startup.
*   The user can use this function to implement the application.
*/

/* USER CODE BEGIN (2) */
/* USER CODE END */

int main(void)
{
/* USER CODE BEGIN (3) */
    rtiInit();
    adcInit();

    // Set ADC to not be interrupt but DMA controlled
    // Set block size to 2, enable block DMA transfer. 2 for 1 samples per channel per conversion in the group which is 2 channels
//    adcREG1->EVDMACR = (2U << 16U) | (1U << 2U);
//    adcREG1->G1DMACR = (2U << 16U) | (1U << 2U);
    adcREG1->EVDMACR = (1U << 3U);
    adcREG1->G1DMACR = (1U << 3U);

    configureAdcDma();

    // RTI is the trigger for the ADC.
    rtiEnableNotification(rtiREG1, rtiNOTIFICATION_COMPARE0); // Enable interrupt for counter 0
    rtiStartCounter(rtiREG1, rtiCOUNTER_BLOCK0); // Enable counter 0

    // Start ADC conversion only once to trigger the DMA the first time
    adcStartConversion(adcREG1, adcGROUP0);
    adcStartConversion(adcREG1, adcGROUP1);

    for(;;)
    {
        // TODO check adcSampleBuffers at an interval
    }
/* USER CODE END */

    return 0;
}


/* USER CODE BEGIN (4) */

static void configureAdcDma(void)
{
    // ADC Group Event specific settings
//    adcGEDmaCtrl.CHCTRL = ADC1_GE_COUNT_DMA_CHAN+1U; // Chain to a DMA channel to keep track of DMA transfers
    adcGEDmaCtrl.CHCTRL = 0U;
    adcGEDmaCtrl.ELCNT = 2U;
    adcGEDmaCtrl.FRCNT = MAX_DMA_TRANSFER_CNT;
    adcGEDmaCtrl.ELSOFFSET = 0;
    adcGEDmaCtrl.FRSOFFSET = 0;
    adcGEDmaCtrl.ELDOFFSET = 8;               // Destination offset per element (4 bytes * 2 samples = 8 bytes)
    adcGEDmaCtrl.FRDOFFSET = (uint32_t)-1024; // Wrap-around when reaching the end of the 256-element buffer (1024 bytes, not 1024 32-bit values)
    adcGEDmaCtrl.RDSIZE = ACCESS_32_BIT;      // Read whole register contents
    adcGEDmaCtrl.WRSIZE = ACCESS_32_BIT;      // Write whole register contents
    adcGEDmaCtrl.TTYPE = FRAME_TRANSFER;      // Trigger sends frame
    adcGEDmaCtrl.AUTOINIT = AUTOINIT_ON;      // Control Sending / auto transfer to loop back around
    adcGEDmaCtrl.SADD = (uint32_t)(&adcSampleBuffers[0].bufferRawADC);
    adcGEDmaCtrl.DADD = (uint32_t)(&(adcREG1->GxBUF[adcGROUP0]));
    adcGEDmaCtrl.PORTASGN = PORTB_READ_PORTA_WRITE; // RAM read, Peripheral Write
    adcGEDmaCtrl.ADDMODERD = ADDR_FIXED;            // Always reads from same buffer location
    adcGEDmaCtrl.ADDMODEWR = ADDR_OFFSET;           // Increment through circular buffer by 2 elements each time

    // ADC GE DMA counter specific settings
//    adcGECountDmaCtrl.CHCTRL = 0U; // End of chain
//    adcGECountDmaCtrl.ELCNT = 1U;
//    adcGECountDmaCtrl.FRCNT = 1U;
//    adcGECountDmaCtrl.ELSOFFSET = 0;
//    adcGECountDmaCtrl.FRSOFFSET = 0;
//    adcGECountDmaCtrl.ELDOFFSET = 0;
//    adcGECountDmaCtrl.FRDOFFSET = 0;
//    adcGECountDmaCtrl.RDSIZE = ACCESS_8_BIT;
//    adcGECountDmaCtrl.WRSIZE = ACCESS_8_BIT;
//    adcGECountDmaCtrl.TTYPE = FRAME_TRANSFER;
//    adcGECountDmaCtrl.AUTOINIT = AUTOINIT_OFF;
//    adcGECountDmaCtrl.SADD = (uint32_t)(&dmaWriteCnt);
//    adcGECountDmaCtrl.DADD = (uint32_t)(&adcSampleBuffers[0].writePtr);
//    adcGECountDmaCtrl.PORTASGN = PORTA_READ_PORTA_WRITE; // RAM read, RAM Write
//    adcGECountDmaCtrl.ADDMODERD = ADDR_INC1;             // Increment through counter array
//    adcGECountDmaCtrl.ADDMODEWR = ADDR_FIXED;            // Always update writePtr

    // Pull DMA out of reset
    dmaEnable();

    // Assign hardware defined request line to the software defined DMA channel. The channel is arbitrary, the request
    // must align with the devices data sheet for DMA.
    dmaReqAssign(adcGEDmaChan, dmaReqlineAdcGE);
//    dmaReqAssign(adcGECountDmaChan, dmaReqlineAdcGECount);

    // Configure the DMA control packet
    dmaSetCtrlPacket(adcGEDmaChan, adcGEDmaCtrl);
//    dmaSetCtrlPacket(adcGECountDmaChan, adcGECountDmaCtrl);

    // Highest DMA priority
    dmaSetPriority(adcGEDmaChan, HIGHPRIORITY);
//    dmaSetPriority(adcGECountDmaChan, HIGHPRIORITY);

    // Enable DMA triggers
    dmaSetChEnable(adcGEDmaChan, DMA_HW);
//    dmaSetChEnable(adcGECountDmaChan, DMA_HW);
}
/* USER CODE END */

  • As an update, the ADC is now successfully converting results at least once (I see the ADC FIFO buffer update). Had some HalCoGen mistakes. But I don't see them being written to the adcSampleBuffer by DMA still. Edit: had the dest and source addresses swapped, fixed that and now see indices 0 and 1 written in the adcSampleBuffer to and nothing else - also updated FRDOFFSET.  I've got the shared memory region set up with HalCoGen and the linker file.

    So I'm still stuck and questioning my DMA packet configurations as I expect the whole buffer to get filled and wrap around automatically

  • Hi Spencer,

    Can you please check this tested ADC-DMA example:

    7750.ADC_with_DMA_RM46.zip

    This is not exactly on the same device, however on same family of controller. So, take this as reference and verify your configurations related to DMA once.

    --
    Thanks & regards,
    Jagadish.

  • Thanks for the example. From the example it seemed that my DMA configuration was okay to get started with. I realized that it was the triggering that seemed problematic with the RTI. Found that I had missed setting COMP0CLR register along with the INTCLRENABLE to auto clear the interrupt flag of the RTI. 

    After properly setting up the RTI I was able to configure everything else properly and solved the issues.