0
\$\begingroup\$

I've connected a TI ADS127L01 to the SPI2 of a STM32F746 mcu via SPI2 and Timer 2 Channel 4 input capture for the data ready signal. As soon the data ready signal is captured, the SPI TX DMA (which is mapped to the TIM2_CH4 DMA) transmits 32bits and the SPI RX DMA receives one sample point. The ADS127L01 is running at 500kSPS.

As long the SPI RX DMA is running in normal mode, all of this works perfectly fine. As soon I set the RX DMA to circular mode, the data is messed up and the SPI transfer can only be started once, even after reinitializing.

To building a moving average, with dynamic amount of mean values, the half transfer and full transfer interrupt are used. Both interrupts fire the same function to calculate those averaging values. As soon the total number of sample points is reached, the TIM2_CH4 input capture is deactivated and SPI is stopped. For any reason this works not reliable and maybe some of you already had similar problems?

Also I have big problems calculating and verifying the CRC. I've tried to calculate the CRC8 using a lookup table as well as the polynome and the STM CRC library but could not get things running. Maybe someone did this for any other TI ADC in combination with the STM32 before and can give me some hints?

For anyone facing a similar task, here are my code snippets which might help.

The source code for the ADS127L01 communication:

/* Includes ------------------------------------------------------------------*/
#include <ads127l01.h>

/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hAds127l01Spi;
TIM_HandleTypeDef hAds127l01Tim;
CRC_HandleTypeDef hAds127l01Crc;

ADS127L01_StatusTypeDef sAds127l01State = ADS127L01_STOP; /* ADS state flag */

int32_t uAds127l01FilterThreshold = 0; /* Threshold for peak detection, activated when > 0 */

int32_t aAds127l01Data[ADS127L01_MAX_DATA_SIZE] = { 0 }; /* Data buffer used for single ADS127L01 values */
uint16_t uAds127l01DataCount = 0; /* Sample points counter */
static uint16_t uAds127l01SamplePoints = 0; /* Total count of sample points */

uint16_t uAds127l01Fault[ADS127L01_MAX_DATA_SIZE] = { 0 }; /* Data buffer used for faulty ADS127L01 values */
static uint16_t uAds127l01FaultCount = 0; /* Faulty sample points counter */
static uint16_t uAds127l01SkipCount = 0; /* Skipped sample points because they were 0 (null) */

static uint32_t aSpiAds127l01TxBuffer = 0xFFFFFFFF; /* SPI Tx Buffer */
static uint32_t aSpiAds127l01RxBuffer[ADS127L01_BUFFERSIZE] = { 0 }; /* SPI Rx Buffer */
static uint32_t aSpiAds127l01RxDoubleBuffer[ADS127L01_BUFFERSIZE] = { 0 }; /* SPI Rx Buffer for double mode */

/* Moving average values */
int32_t uAds127l01MovingValue = 0; /* Continuous moving average value */
static uint32_t aAds127l01MovingBuffer[ADS127L01_MOVING_AVERAGE] = { 0 }; /* Continuous moving average buffer */

/* Averaging settings 1 AVG = 2us (@500 kSPS) */
uint16_t uAds127l01AvgSamplePoints[ADS127L01_AVERAGING_STEPS_MAX] = { 100, 200, 300, 400, 500 }; /* Amount of sample points for belonging averaging step */
uint16_t uAds127l01AvgMean[ADS127L01_AVERAGING_STEPS_MAX] = { 1, 2, 4, 8, 16 }; /* Mean counter, amount of values for each sample point */

uint16_t uAds127l01AvgCurrentStep = 0; /* Current averaging step */
int64_t uwAds127l01AvgCurrentSampleValue = 0; /* Current sample points within current averaging */
uint16_t uAds127l01AvgCurrentSamplePoints = 0; /* Current averaging sample points */

/* CRC8 table, not working at all */
static const uint8_t ADS127L01_CrcTable[] = { 0x00, 0x03, 0x06, 0x05, 0x0C,
        0x0F, 0x0A, 0x09, 0x18, 0x1B, 0x1E, 0x1D, 0x14, 0x17, 0x12, 0x11, 0x30,
        0x33, 0x36, 0x35, 0x3C, 0x3F, 0x3A, 0x39, 0x28, 0x2B, 0x2E, 0x2D, 0x24,
        0x27, 0x22, 0x21, 0x60, 0x63, 0x66, 0x65, 0x6C, 0x6F, 0x6A, 0x69, 0x78,
        0x7B, 0x7E, 0x7D, 0x74, 0x77, 0x72, 0x71, 0x50, 0x53, 0x56, 0x55, 0x5C,
        0x5F, 0x5A, 0x59, 0x48, 0x4B, 0x4E, 0x4D, 0x44, 0x47, 0x42, 0x41, 0xC0,
        0xC3, 0xC6, 0xC5, 0xCC, 0xCF, 0xCA, 0xC9, 0xD8, 0xDB, 0xDE, 0xDD, 0xD4,
        0xD7, 0xD2, 0xD1, 0xF0, 0xF3, 0xF6, 0xF5, 0xFC, 0xFF, 0xFA, 0xF9, 0xE8,
        0xEB, 0xEE, 0xED, 0xE4, 0xE7, 0xE2, 0xE1, 0xA0, 0xA3, 0xA6, 0xA5, 0xAC,
        0xAF, 0xAA, 0xA9, 0xB8, 0xBB, 0xBE, 0xBD, 0xB4, 0xB7, 0xB2, 0xB1, 0x90,
        0x93, 0x96, 0x95, 0x9C, 0x9F, 0x9A, 0x99, 0x88, 0x8B, 0x8E, 0x8D, 0x84,
        0x87, 0x82, 0x81, 0x83, 0x80, 0x85, 0x86, 0x8F, 0x8C, 0x89, 0x8A, 0x9B,
        0x98, 0x9D, 0x9E, 0x97, 0x94, 0x91, 0x92, 0xB3, 0xB0, 0xB5, 0xB6, 0xBF,
        0xBC, 0xB9, 0xBA, 0xAB, 0xA8, 0xAD, 0xAE, 0xA7, 0xA4, 0xA1, 0xA2, 0xE3,
        0xE0, 0xE5, 0xE6, 0xEF, 0xEC, 0xE9, 0xEA, 0xFB, 0xF8, 0xFD, 0xFE, 0xF7,
        0xF4, 0xF1, 0xF2, 0xD3, 0xD0, 0xD5, 0xD6, 0xDF, 0xDC, 0xD9, 0xDA, 0xCB,
        0xC8, 0xCD, 0xCE, 0xC7, 0xC4, 0xC1, 0xC2, 0x43, 0x40, 0x45, 0x46, 0x4F,
        0x4C, 0x49, 0x4A, 0x5B, 0x58, 0x5D, 0x5E, 0x57, 0x54, 0x51, 0x52, 0x73,
        0x70, 0x75, 0x76, 0x7F, 0x7C, 0x79, 0x7A, 0x6B, 0x68, 0x6D, 0x6E, 0x67,
        0x64, 0x61, 0x62, 0x23, 0x20, 0x25, 0x26, 0x2F, 0x2C, 0x29, 0x2A, 0x3B,
        0x38, 0x3D, 0x3E, 0x37, 0x34, 0x31, 0x32, 0x13, 0x10, 0x15, 0x16, 0x1F,
        0x1C, 0x19, 0x1A, 0x0B, 0x08, 0x0D, 0x0E, 0x07, 0x04, 0x01, 0x02 };

/* Private function prototypes -----------------------------------------------*/
static void ADS127L01_WriteConfig(void);
static void ADS127L01_ReadConfig(void);
static void ADS127L01_StartDevice(void);
static void ADS127L01_StopDevice(void);
static void ADS127L01_ResetDevice(void);
static void ADS127L01_ReadData(void);
static uint8_t ADS127L01_CalculateCrc(uint8_t *pData, uint16_t len);

static void ADS127L01_SPI_Config(void);
static void ADS127L01_TIM_Config(void);
static void ADS127L01_CRC_Config(void);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief  Configure ADS127L01 peripheral
 *          1. TIM IC fires at Data Ready (each 2us @500kSPS)
 *          2. SPI Half Cplt will be executed for first 512 samples
 *          3. SPI Cplt will be executed for second 512 samples
 * @param  None
 * @retval None
 */
void ADS127L01_Config(void) {
    /*##-1- Configure ADS127L01 peripheral ###################################*/
    ADS127L01_SPI_Config();
    ADS127L01_TIM_Config();

    /*##-2- Configure ADS127L01 to send CRC8 #################################*/
//  ADS127L01_WriteConfig(); /* Status Word Contents: CRC-8 */
//  ADS127L01_CRC_Config();

    /*##-2- Set ADS127L01 state flag #########################################*/
    sAds127l01State = ADS127L01_OK;
}

/**
 * @brief  ADS127L01 start measurement
 * @param  None
 * @retval None
 */
void ADS127L01_Start(void) {
    if (sAds127l01State != ADS127L01_OK) {
        ADS127L01_Stop();
    }

    /*##-1- Reset counter and set ADS127L01 state flag #######################*/
    uAds127l01DataCount = 0;
    uAds127l01FaultCount = 0;
    uAds127l01SkipCount = 0;

    uAds127l01AvgCurrentStep = 0;
    uwAds127l01AvgCurrentSampleValue = 0;
    uAds127l01AvgCurrentSamplePoints = uAds127l01AvgMean[uAds127l01AvgCurrentStep];

    /* Get amount of total sample points */
    uAds127l01SamplePoints = 0;
    for (uint8_t i = ADS127L01_AVERAGING_STEPS_MAX; i >= 0; i--) {
        if (uAds127l01AvgSamplePoints[i] != 0) {
            uAds127l01SamplePoints = uAds127l01AvgSamplePoints[i];
            break;
        }
    }
    if (uAds127l01SamplePoints == 0 || uAds127l01SamplePoints > ADS127L01_MAX_DATA_SIZE) {
        uAds127l01SamplePoints = ADS127L01_DEFAULT_AVG_SAMPLES;
    }

    sAds127l01State = ADS127L01_BUSY;
    uStatus |= STATUS_ADS127L01_RUNNING;

    /*##-2- Set ADS127L01 data register to current value #####################*/
    ADS127L01_ReadData();

    /*##-3- Start SPI transmit/receive mode ##################################*/
    if (HAL_SPI_TransmitReceive_DMA(&hAds127l01Spi, (uint8_t *) &aSpiAds127l01TxBuffer, \
            (uint8_t *) &aSpiAds127l01RxBuffer, ADS127L01_BUFFERSIZE * ADS127L01_SAMPLE_LENGTH) != HAL_OK) {
        /* Starting Error */
        Error_Handler(__FILE__, __LINE__);
    }

    /*##-4- Start timer in input capture interrupt mode (DRDY) ###############*/
    if (HAL_TIM_IC_Start_DMA(&hAds127l01Tim, ADS127L01_TIM_IC_CHANNEL, NULL, 0) != HAL_OK) {
        /* Starting Error */
        Error_Handler(__FILE__, __LINE__);
    }
}

/**
 * @brief  ADS127L01 stop measurement
 * @param  None
 * @retval None
 */
void ADS127L01_Stop(void) {
    /*##-1- Stop timer in input capture interrupt mode (DRDY) ################*/
    if (HAL_TIM_IC_Stop_DMA(&hAds127l01Tim, ADS127L01_TIM_IC_CHANNEL) != HAL_OK) {
        /* Stopping Error */
        Error_Handler(__FILE__, __LINE__);
    }

    /*##-2- Disable SPI ######################################################*/
    __HAL_SPI_DISABLE(&hAds127l01Spi);

    /*##-3- Stop the SPI DMA Transfer ########################################*/
    if (HAL_DMA_GetState(hAds127l01Spi.hdmarx) == HAL_DMA_STATE_BUSY) {
        if (HAL_SPI_DMAStop(&hAds127l01Spi) != HAL_OK) {
            /* Stopping SPI DMA Error */
            Error_Handler(__FILE__, __LINE__);
        }
    }
    /* Clear DMA error codes */
    hAds127l01Spi.hdmarx->ErrorCode = HAL_DMA_ERROR_NONE;
    hAds127l01Spi.hdmatx->ErrorCode = HAL_DMA_ERROR_NONE;

    /*##-4- Reinitialize ADS #################################################*/
//  __SPI2_FORCE_RESET();
//  __SPI2_RELEASE_RESET();
//  ADS127L01_SPI_Config();

    /*##-5- Reset ADS state flag #############################################*/
    sAds127l01State = ADS127L01_STOP;
    uStatus &= ~(STATUS_ADS127L01_RUNNING);
}

/**
 * @brief  ADS127L01 write register (0100 rrrr 0000 nnnn)
 *          The wREG command writes the number of bytes specified by nnnn
 *          (number of registers to be written – 1) to the device configuration
 *          register, starting at register address rrrr. The command is
 *          completed after nnnn + 1 bytes are clocked in after the WREG command
 *          byte. For example, the command to write two registers (nnnn = 0001)
 *          starting at register address 01h (rrrr = 0001) is 0100 0001 0000 0001
 *          as shown in Figure 93. Two bytes follow the command to write the
 *          contents to the registers. The frame must extend by the proper
 *          number of SCLKs to write data to the registers.
 * @param  None
 * @retval None
 */
static void ADS127L01_WriteConfig(void) {
    uint8_t startAddress = 1;
    uint8_t length = 1;
    uint8_t config = (ADS127L01_CRCB);

    /* Write CONFIG register */
    uint8_t writeCommand[3] = { (0b00100000 | startAddress), (length - 1), config };

    if (HAL_SPI_Transmit(&hAds127l01Spi, (uint8_t *) &writeCommand, length + 2, 1000) != HAL_OK) {
        /* Transmit Error */
        Error_Handler(__FILE__, __LINE__);
    }
}

static void ADS127L01_ReadConfig(void) {
    uint8_t startAddress = 0;
    uint8_t length = 1;

    /* Read CONFIG register */
    uint8_t readCommand[2] = { (0b00100000 | startAddress), (length - 1) };
    uint8_t response[length];

    if (HAL_SPI_TransmitReceive(&hAds127l01Spi, (uint8_t *) &readCommand, (uint8_t *) &response, 5, 1000) != HAL_OK) {
        /* Transmit Receive Error */
        Error_Handler(__FILE__, __LINE__);
    }
}

static void ADS127L01_ResetDevice(void) {
    /* Reset device */
    uint8_t writeCommand[1] = { 0b00000110 };
    if (HAL_SPI_Transmit(&hAds127l01Spi, (uint8_t *) &writeCommand, 1, 1000) != HAL_OK) {
        /* Reset Device Error */
        Error_Handler(__FILE__, __LINE__);
    }
}

static void ADS127L01_StartDevice(void) {
    /* Start device */
    uint8_t writeCommand[1] = { 0b00001000 };
    if (HAL_SPI_Transmit(&hAds127l01Spi, (uint8_t *) &writeCommand, 1, 1000) != HAL_OK) {
        /* Start Device Error */
        Error_Handler(__FILE__, __LINE__);
    }
}

static void ADS127L01_StopDevice(void) {
    /* Stop device */
    uint8_t writeCommand[1] = { 0b00001010 };
    if (HAL_SPI_Transmit(&hAds127l01Spi, (uint8_t *) &writeCommand, 1, 1000) != HAL_OK) {
        /* Stop Device Error */
        Error_Handler(__FILE__, __LINE__);
    }
}

static void ADS127L01_ReadData(void) {
    /* Stop device */
    uint8_t writeCommand[1] = { 0b00010010 };
    if (HAL_SPI_Transmit(&hAds127l01Spi, (uint8_t *) &writeCommand, 1, 1000) != HAL_OK) {
        /* Stop Device Error */
        Error_Handler(__FILE__, __LINE__);
    }
}

/**
 * @brief  Calculate CRC3
 * @param  pData: pointer to Ads127l01 Rx data buffer
 * @param  len: data command length.
 * @retval crc: Calculated CRC3 value
 */
static uint8_t ADS127L01_CalculateCrc(uint8_t *pData, uint16_t len) {
    uint8_t uCRC = 0x00; /* high byte of CRC initialized */
    uint16_t uIndex;

    /* pass through message buffer */
    while (len--) {
        uIndex = uCRC ^ *pData++; /* calculate the CRC  */
        uCRC = ADS127L01_CrcTable[uIndex];
    }
    return ((uint8_t) uCRC);
}

/******************************************************************************/
/*                      Interrupt & Callback Functions                        */
/******************************************************************************/

/**
 * @brief  ADS127L01 Transfer completed callback, will be executed when amount
 *         of sample points is reached.
 * @param  None
 * @retval None
 */
void ADS127L01_TransferCpltCallback(void) {
    /*##-1- Stop ADS127L01 DMA transfer ######################################*/
    ADS127L01_Stop();

    /*##-2- Set ADS127L01 state flag #########################################*/
    sAds127l01State = ADS127L01_OK;
}

/**
 * @brief  ADS Half Transfer completed callback, will be executed by
 *         HAL_SPI_TxRxHalfCpltCallback and HAL_SPI_TxRxCpltCallback when in
 *         normal mode.
 * @param  pAdcData: pointer to reception data buffer
 * @param  offset: offset where to start with averaging
 * @param  len: amount of data
 * @retval None
 */
void ADS127L01_HalfTransferCpltCallback(uint32_t *pAdcData, uint16_t offset, uint16_t len) {
    uint16_t avg = uAds127l01AvgCurrentSamplePoints;
    int64_t tmp = uwAds127l01AvgCurrentSampleValue;
    uint32_t byteorder = 0;
    int32_t value = 0;

    for (uint16_t i = offset; i < len; i++) {
        /*##-1- Check CRC Checksum, CRC8 must be set! ########################*/
//      ADS127L01_CalculateCrc((uint8_t *)&pAdcData[i], 6);
//      wCRCValue = HAL_CRC_Calculate(&hAds127l01Crc, (uint32_t *)&pAdcData[i], 0x03);

        /*##-2- Rearrange byte order #########################################*/
        /* Rearrange byte order */
        byteorder = (pAdcData[i] & 0x00ff0000) >> 16; /* first byte */
        byteorder |= pAdcData[i] & 0x0000ff00; /* second byte */
        byteorder |= (pAdcData[i] & 0x000000ff) << 16; /* third byte */

        /* Invert signal because hardware input channels are swapped */
        if (byteorder & 0x00800000) {
            value = ((int32_t) ((~byteorder) & 0x007FFFFF));
        } else {
            value = (-(int32_t) (byteorder & 0x007FFFFF));
        }

        /*##-3- Detect wrong values, measuring error or overflow #############*/
        /* Check for out of range input bit (INP) */
        if ((pAdcData[i] & 0x08000000) != 0) {
            uAds127l01Fault[uAds127l01FaultCount] = uAds127l01DataCount;
            uAds127l01FaultCount++;
        }
        /* Check for 0 (null) element */
        if (value == 0) {
            uAds127l01SkipCount++;
            /* Skip this value, error during transmission or during conversion */
//          continue;
        }

        /*##-4- Calculate sum for averaging ##################################*/
        if (avg > 0) {
            tmp += value;
            avg--;
        }

        /*##-5- Create new sample point ######################################*/
        if (avg == 0) {
            /* Calculate averaging value */
            aAds127l01Data[uAds127l01DataCount] = (int32_t) (tmp / uAds127l01AvgMean[uAds127l01AvgCurrentStep]);
            uAds127l01DataCount++;

            /* End if amount of sample points reached */
            if (uAds127l01DataCount >= uAds127l01SamplePoints) {
                sAds127l01State = ADS127L01_COMPLETE;
                ADS127L01_TransferCpltCallback();
                return;
            }

            /* Check for next averaging stage */
            if (uAds127l01DataCount >= uAds127l01AvgSamplePoints[uAds127l01AvgCurrentStep]) {
                uAds127l01AvgCurrentStep++;
            }

            /* Reset averaging counter */
            avg = uAds127l01AvgMean[uAds127l01AvgCurrentStep];
            tmp = 0;
        }
    }

    /* Keep averaging values for next 512 sample points */
    uwAds127l01AvgCurrentSampleValue = tmp;
    uAds127l01AvgCurrentSamplePoints = avg;
}

/**
 * @brief  This function handles DMA Rx interrupt request. It is executed every
 *         512 samples and triggers HAL_SPI_TxRxHalfCpltCallback as well as
 *         HAL_SPI_TxRxCpltCallback.
 * @param  None
 * @retval None
 */
void ADS127L01_SPI_DMA_RX_IRQHandler(void) {
    HAL_DMA_IRQHandler(hAds127l01Spi.hdmarx);
}

/**
 * @brief  This function handles DMA Tx interrupt request. Because all DMA
 *         interrupts are handled by the DMA Rx interrupt it is not needed.
 * @param  None
 * @retval None
 */
void ADS127L01_SPI_DMA_TX_IRQHandler(void) {
//  HAL_DMA_IRQHandler(hAds127l01Spi.hdmatx);
}

/**
 * @brief  This function handles TIM input capture interrupt request. Because
 *         all DMA interrupts are handled by the DMA Rx interrupt it is not
 *         needed.
 * @param  None
 * @retval None
 */
void ADS127L01_TIM_IC_IRQHandler(void) {
//  HAL_TIM_IRQHandler(&hAds127l01Tim);
}

/******************************************************************************/
/*                          Peripheral Initialization                         */
/******************************************************************************/

/**
 * @brief  Configuration SPI
 * @param  None
 * @retval None
 */
static void ADS127L01_SPI_Config(void) {
    /*##-1- Configure the SPI peripheral #####################################*/
    /* Set the SPI parameters */
    hAds127l01Spi.Instance = ADS127L01_SPI;
    hAds127l01Spi.Init.Mode = ADS127L01_SPI_MODE;

    hAds127l01Spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
    hAds127l01Spi.Init.Direction = SPI_DIRECTION_2LINES;
    hAds127l01Spi.Init.CLKPolarity = SPI_POLARITY_LOW;
    hAds127l01Spi.Init.CLKPhase = SPI_PHASE_2EDGE; // SPI_PHASE_1EDGE SPI_PHASE_2EDGE

    hAds127l01Spi.Init.DataSize = SPI_DATASIZE_8BIT;
    hAds127l01Spi.Init.FirstBit = SPI_FIRSTBIT_MSB;

    hAds127l01Spi.Init.TIMode = SPI_TIMODE_DISABLE;
    hAds127l01Spi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;

    hAds127l01Spi.Init.NSS = SPI_NSS_HARD_OUTPUT;
    hAds127l01Spi.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;

    if (HAL_SPI_Init(&hAds127l01Spi) != HAL_OK) {
        /* Initialization Error */
        Error_Handler(__FILE__, __LINE__);
    }
}

/**
 * @brief  Configuration Timer
 * @param  None
 * @retval None
 */
static void ADS127L01_TIM_Config(void) {
    TIM_IC_InitTypeDef sConfig;

    /*##-1- Configure the TIM peripheral #####################################*/
    /* Initialize timer input capture (data ready) peripheral */
    hAds127l01Tim.Instance = ADS127L01_TIM_IC;
    hAds127l01Tim.Init.Period = 0xFFFF;
    hAds127l01Tim.Init.Prescaler = 0;
    hAds127l01Tim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    hAds127l01Tim.Init.CounterMode = TIM_COUNTERMODE_UP;
    hAds127l01Tim.Init.RepetitionCounter = 0;

    if (HAL_TIM_IC_Init(&hAds127l01Tim) != HAL_OK) {
        /* Initialization Error */
        Error_Handler(__FILE__, __LINE__);
    }

    /*##-2- Configure the Input Capture channel ##############################*/
    /* Configure the Input Capture */
    sConfig.ICPolarity = TIM_ICPOLARITY_FALLING;
    sConfig.ICSelection = TIM_ICSELECTION_DIRECTTI;
    sConfig.ICPrescaler = TIM_ICPSC_DIV1;
    sConfig.ICFilter = 0;

    if (HAL_TIM_IC_ConfigChannel(&hAds127l01Tim, &sConfig, ADS127L01_TIM_IC_CHANNEL) != HAL_OK) {
        /* Configuration Error */
        Error_Handler(__FILE__, __LINE__);
    }
}

/**
 * @brief  Configuration CRC
 * @param  None
 * @retval None
 */
static void ADS127L01_CRC_Config(void) {
    hAds127l01Crc.Instance = CRC;
    hAds127l01Crc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;

    hAds127l01Crc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE;
    hAds127l01Crc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_DISABLE;
    hAds127l01Crc.Init.InputDataInversionMode = CRC_INPUTDATA_FORMAT_BYTES;
    hAds127l01Crc.Init.OutputDataInversionMode =
            CRC_OUTPUTDATA_INVERSION_ENABLE;
    hAds127l01Crc.Init.GeneratingPolynomial = ADS127L01_CRC_POLY;

    hAds127l01Crc.Init.CRCLength = CRC_POLYLENGTH_8B;
    hAds127l01Crc.Init.InitValue = 0x0000;

    if (HAL_CRC_Init(&hAds127l01Crc) != HAL_OK) {
        /* Configuration Error */
        Error_Handler(__FILE__, __LINE__);
    }
}

/******************************************************************************/
/*                          Hardware Initialization                           */
/******************************************************************************/

/**
 * @brief  SPI MSP Initialization configures the hardware resources.
 * @param  hSpi: SPI handle pointer
 * @retval None
 */
void ADS127L01_SPI_MspInit(SPI_HandleTypeDef *hSpi) {
    static DMA_HandleTypeDef hSpiTxDma;
    static DMA_HandleTypeDef hSpiRxDma;

    GPIO_InitTypeDef GPIO_InitStruct;

    /*##-1- Enable peripherals and GPIO Clocks ###############################*/
    /* Enable GPIO TX/RX clock */
    ADS127L01_SPI_SCK_GPIO_CLK_ENABLE();
    ADS127L01_SPI_MISO_GPIO_CLK_ENABLE();
    ADS127L01_SPI_MOSI_GPIO_CLK_ENABLE();
    ADS127L01_SPI_NSS_GPIO_CLK_ENABLE();

    /* Enable SPI1 clock */
    ADS127L01_SPI_CLK_ENABLE();

    /* Enable DMA clock */
    ADS127L01_SPI_DMA_TX_CLK_ENABLE();
    ADS127L01_SPI_DMA_RX_CLK_ENABLE();

    /*##-2- Configure peripheral GPIO ########################################*/
    /* SPI SCK GPIO pin configuration */
    GPIO_InitStruct.Pin = ADS127L01_SPI_SCK_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = ADS127L01_SPI_SCK_AF;
    HAL_GPIO_Init(ADS127L01_SPI_SCK_GPIO_PORT, &GPIO_InitStruct);

    /* SPI MISO GPIO pin configuration */
    GPIO_InitStruct.Pin = ADS127L01_SPI_MISO_PIN;
    GPIO_InitStruct.Alternate = ADS127L01_SPI_MISO_AF;
    HAL_GPIO_Init(ADS127L01_SPI_MISO_GPIO_PORT, &GPIO_InitStruct);

    /* SPI MOSI GPIO pin configuration */
    GPIO_InitStruct.Pin = ADS127L01_SPI_MOSI_PIN;
    GPIO_InitStruct.Alternate = ADS127L01_SPI_MOSI_AF;
    HAL_GPIO_Init(ADS127L01_SPI_MOSI_GPIO_PORT, &GPIO_InitStruct);

    /* SPI NSS GPIO pin configuration */
    GPIO_InitStruct.Pin = ADS127L01_SPI_NSS_PIN;
    GPIO_InitStruct.Alternate = ADS127L01_SPI_NSS_AF;
    HAL_GPIO_Init(ADS127L01_SPI_NSS_GPIO_PORT, &GPIO_InitStruct);

    /*##-3- Configure the DMA ################################################*/
    /* Configure the DMA handler for Reception process */
    hSpiRxDma.Instance = ADS127L01_SPI_DMA_RX_STREAM;
    hSpiRxDma.Init.Channel = ADS127L01_SPI_DMA_RX_CHANNEL;

    hSpiRxDma.Init.Mode = DMA_CIRCULAR; // DMA_NORMAL DMA_CIRCULAR
    hSpiRxDma.Init.Direction = DMA_PERIPH_TO_MEMORY;

    hSpiRxDma.Init.PeriphInc = DMA_PINC_DISABLE; /* Static Peripheral: 4 x uint8_t */
    hSpiRxDma.Init.PeriphBurst = DMA_PBURST_INC4;
    hSpiRxDma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

    hSpiRxDma.Init.MemInc = DMA_MINC_ENABLE; /* Dynamic Memory: 1 x uint32_t */
    hSpiRxDma.Init.MemBurst = DMA_MBURST_SINGLE;
    hSpiRxDma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;

    hSpiRxDma.Init.Priority = DMA_PRIORITY_VERY_HIGH;

    if (HAL_DMA_Init(&hSpiRxDma) != HAL_OK) {
        /* Initialization Error */
        Error_Handler(__FILE__, __LINE__);
    }

    /* Associate the initialized DMA handle to the the SPI handle */
    __HAL_LINKDMA(hSpi, hdmarx, hSpiRxDma);

    /* Configure the DMA handler for Transmission process */
    hSpiTxDma.Instance = ADS127L01_SPI_DMA_TX_STREAM;
    hSpiTxDma.Init.Channel = ADS127L01_SPI_DMA_TX_CHANNEL;
    hSpiTxDma.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    hSpiTxDma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; /* Check RM0385 p.232 */
    hSpiTxDma.Init.Mode = DMA_CIRCULAR;
    hSpiTxDma.Init.Direction = DMA_MEMORY_TO_PERIPH;

    hSpiTxDma.Init.MemInc = DMA_MINC_DISABLE; /* Static Memory: 1 x uint32_t */
    hSpiTxDma.Init.MemBurst = DMA_MBURST_SINGLE;
    hSpiTxDma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;

    hSpiTxDma.Init.PeriphInc = DMA_PINC_DISABLE; /* Static Peripheral: 4 x uint8_t */
    hSpiTxDma.Init.PeriphBurst = DMA_PBURST_INC4;
    hSpiTxDma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

    hSpiTxDma.Init.Priority = DMA_PRIORITY_HIGH;

    if (HAL_DMA_Init(&hSpiTxDma) != HAL_OK) {
        /* Initialization Error */
        Error_Handler(__FILE__, __LINE__);
    }

    /* Associate the initialized DMA handle to the the SPI handle */
    __HAL_LINKDMA(hSpi, hdmatx, hSpiTxDma);

    /* Associate the initialized DMA handle to the the TIM handle */
    __HAL_LINKDMA(&hAds127l01Tim, hdma[ADS127L01_TIM_IC_DMA_ID], hSpiTxDma);

    /*##-4- Configure the NVIC for DMA receive ###############################*/
    /* NVIC configuration for DMA transfer complete interrupt (SPIx_RX) */
    HAL_NVIC_SetPriority(ADS127L01_SPI_DMA_RX_IRQn, ADS127L01_IRQPriority, 2);
    HAL_NVIC_EnableIRQ(ADS127L01_SPI_DMA_RX_IRQn);
}

/**
 * @brief  SPI MSP De-Initialization frees the hardware resources.
 * @param  hSpi: SPI handle pointer
 * @retval None
 */
void ADS127L01_SPI_MspDeInit(SPI_HandleTypeDef *hSpi) {
    /*##-1- Reset peripherals ################################################*/
    ADS127L01_SPI_FORCE_RESET();
    ADS127L01_SPI_RELEASE_RESET();

    /*##-2- Disable peripherals and GPIO Clocks ##############################*/
    HAL_GPIO_DeInit(ADS127L01_SPI_SCK_GPIO_PORT, ADS127L01_SPI_SCK_PIN);
    HAL_GPIO_DeInit(ADS127L01_SPI_MISO_GPIO_PORT, ADS127L01_SPI_MISO_PIN);
    HAL_GPIO_DeInit(ADS127L01_SPI_MOSI_GPIO_PORT, ADS127L01_SPI_MOSI_PIN);
    HAL_GPIO_DeInit(ADS127L01_SPI_NSS_GPIO_PORT, ADS127L01_SPI_NSS_PIN);

    /*##-3- Disable the DMA ##################################################*/
    /* De-Initialize the DMA associated to reception process */
    if (hSpi->hdmarx != 0) {
        HAL_DMA_DeInit(hSpi->hdmarx);
    }
    /* De-Initialize the DMA associated to transmission process */
    if (hSpi->hdmatx != 0) {
        HAL_DMA_DeInit(hSpi->hdmatx);
    }

    /*##-4- Disable the NVIC for DMA #########################################*/
    HAL_NVIC_DisableIRQ(ADS127L01_SPI_DMA_RX_IRQn);

    /*##-5- Configure the NVIC for SPI #######################################*/
    HAL_NVIC_SetPriority(ADS127L01_SPI_IRQn, ADS127L01_IRQPriority, 0);
    HAL_NVIC_EnableIRQ(ADS127L01_SPI_IRQn);
}

/**
 * @brief  TIM MSP Initialization configures the hardware resources.
 * @param  hTim: TIM handle pointer
 * @retval None
 */
void ADS127L01_TIM_IC_MspInit(TIM_HandleTypeDef *hTim) {
    GPIO_InitTypeDef GPIO_InitStruct;

    /*##-1- Enable peripherals and GPIO Clocks ###############################*/
    /* Timer input capture (data ready) Peripheral clock enable */
    ADS127L01_TIM_IC_CLK_ENABLE();

    /* Enable GPIO channels Clock */
    ADS127L01_TIM_IC_GPIO_CLK_ENABLE();

    /* Configure (ADS127L01_TIM_Channel) in Alternate function, push-pull and high speed */
    GPIO_InitStruct.Pin = ADS127L01_TIM_IC_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // GPIO_MODE_AF_OD GPIO_MODE_AF_PP
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = ADS127L01_TIM_IC_GPIO_AF;

    HAL_GPIO_Init(ADS127L01_TIM_IC_GPIO_PORT, &GPIO_InitStruct);
}

/**
 * @brief  TIM MSP De-Initialization frees the hardware resources.
 * @param  hTim: TIM handle pointer
 * @retval None
 */
void ADS127L01_TIM_IC_MspDeInit(TIM_HandleTypeDef *hTim) {
    /*##-1- Reset peripherals ################################################*/
    ADS127L01_TIM_IC_FORCE_RESET();
    ADS127L01_TIM_IC_RELEASE_RESET();

    /*##-2- Disable peripherals and GPIO Clocks ##############################*/
    HAL_GPIO_DeInit(ADS127L01_TIM_IC_GPIO_PORT, ADS127L01_TIM_IC_GPIO_PIN);

    /*##-3- Disable the NVIC for TIM #########################################*/
    HAL_NVIC_DisableIRQ(ADS127L01_TIM_IC_IRQn);
}

/********************************* END OF FILE ********************************/

And both relavent interrupt functions:

/**
 * @brief  TxRx Half Transfer completed callback.
 * @param  hSpi: pointer to a SPI_HandleTypeDef structure that contains
 *         the configuration information for SPI module.
 * @retval None
 */
void HAL_SPI_TxRxHalfCpltCallback(SPI_HandleTypeDef *hSpi) {
#ifdef ACTIVATE_ADS127L01
    if (hSpi->Instance == ADS127L01_SPI) {
        if (sAds127l01State == ADS127L01_BUSY) {
            /* Run half transfer complete callback for lower buffer half */
            ADS127L01_HalfTransferCpltCallback((uint32_t *)hSpi->pRxBuffPtr, \
                    0, ADS127L01_BUFFERSIZE/2);
        }
    }
#endif
}

/**
 * @brief  TxRx Transfer completed callback.
 * @param  hSpi: pointer to a SPI_HandleTypeDef structure that contains
 *         the configuration information for SPI module.
 * @retval None
 */
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hSpi) {
#ifdef ACTIVATE_ADS127L01
    if (hSpi->Instance == ADS127L01_SPI) {
        if (sAds127l01State == ADS127L01_BUSY) {
            /* Run half transfer complete callback for upper buffer half */
            ADS127L01_HalfTransferCpltCallback((uint32_t *)hSpi->pRxBuffPtr, \
                    ADS127L01_BUFFERSIZE/2, ADS127L01_BUFFERSIZE);
        }
    }
#endif
}

The body is limited to 30000 chars, thats why I couldn't add the header file, sorry.

\$\endgroup\$
  • \$\begingroup\$ What do you mean the data is messed up? Have you checked the DMA destination buffer? Maybe the data is there, but you're just reading it from the wrong start location? And what do you mean your mean average function works not reliable? We will need more information to help you debug. \$\endgroup\$ – Hein Wessels Jul 16 '18 at 19:22
  • \$\begingroup\$ As the DMA destination buffer does not changed when setting the DMA to circular mode, everything should be fine. Each DMA transfere increases the destination buffer address once by 32bit. \$\endgroup\$ – MFH Jul 20 '18 at 8:27
  • \$\begingroup\$ I guess the average function works correctly, but of cource wrong ADC values distort the mean values. Nevertheless, in circular mode ADS127L01_HalfTransferCpltCallback might be the problem. I also checked the runtime of the function for ADS127L01_BUFFERSIZE/2 (512 Samples) which is little smaller than the transfer time for the same amount of samples. \$\endgroup\$ – MFH Jul 20 '18 at 8:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.