AnsweredAssumed Answered

STM32F1xx I2C Receive with HAL

Question asked by Tom Eaton on Sep 4, 2017

I am trying to interface with an ADS1015 using an STM32F103.  I am having problems reading two bytes from the ADS1015. The first byte is received perfectly, but the second byte is exactly the same as the first byte which is incorrect. I think this is because the master (STM32) is not acknowledging the bytes being received. This can be seen below. This is what should be seen according to the datasheet. Datasheet timing However instead this is seen

You can see that the master should be pulling the line low at these points (Acknowledging) but it is not doing this. Here is my code

#include "stm32f1xx.h"
#include "stm32f1xx_hal.h"
#include "stm32f1xx_hal_conf.h"

#define I2C_SPEEDCLOCK 100000

I2C_HandleTypeDef I2cHandle;
UART_HandleTypeDef UartHandle;


__IO ITStatus UartReady = RESET;

void SystemClock_Config(void);
void Startup_Sequence(void);
void Error_Handler(void);
void i2c1_send_data(uint16_t addr, uint8_t* data, uint8_t length);
void i2c1_receive_data(uint16_t addr, uint8_t* data, uint8_t length);
static void i2cUnstick(void);

/**
* This function is called when transmitting
* @param UartHandle [Pointer to UartHandle]
*/

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle) {
    UartReady = SET;
}

/**
* This function is called when receiving
* @param UartHandle [Pointer to UartHandle]
*/

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) {
    UartReady = SET;
}

/**
* Associates the interrupt handler with the UartHandle
*/

void USART1_IRQHandler(void) {
    HAL_UART_IRQHandler(&UartHandle);
}

int main(void)
{
     HAL_Init();
     SystemInit();
     SystemClock_Config();

     GPIO_InitTypeDef  GPIO_InitStruct;
     __GPIOC_CLK_ENABLE();
     __GPIOB_CLK_ENABLE();
    __GPIOA_CLK_ENABLE();
     __HAL_RCC_I2C1_CLK_ENABLE();
    __HAL_RCC_USART1_CLK_ENABLE();

     //Configuring pin for onboard LED.
     GPIO_InitStruct.Pin = GPIO_PIN_13;
     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    //Configuring SDA and SCL pins for I2C.
    GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    // Setup UART TX Pin
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    //Setup UART RX Pin
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    UartHandle.Instance = USART1;
    UartHandle.Init.BaudRate = 9600;
    UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
    UartHandle.Init.StopBits = UART_STOPBITS_1;
    UartHandle.Init.Parity = UART_PARITY_NONE;
    UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    UartHandle.Init.Mode = UART_MODE_TX_RX;

    if(HAL_UART_Init(&UartHandle) != HAL_OK) {
        Error_Handler();
    }

    HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);
    HAL_NVIC_EnableIRQ(USART1_IRQn);

    I2cHandle.Instance = I2C1;
    I2cHandle.Init.ClockSpeed = I2C_SPEEDCLOCK;
    I2cHandle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;

    HAL_NVIC_SetPriority(I2C1_ER_IRQn, 0, 1);
    HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
    HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 1);
    HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);

    if (HAL_I2C_Init(&I2cHandle) != HAL_OK) {
         Error_Handler();
    }

     Startup_Sequence();
    uint16_t config;
    uint8_t configRegister = 1;

    i2c1_send_data(0b10010000, &configRegister, 1);
    i2c1_receive_data(0b10010000, &config, 1);
    i2c1_receive_data(0b10010000, &config, 1);
    //HAL_UART_Transmit_IT(&UartHandle, &MSB, 1);
    //HAL_UART_Transmit_IT(&UartHandle, &config, 1);
     while (1) {

     }
}

/**
* Configures System Clock. Configured as follows:
*                System Clock source = PLL (HSE)
*                SYSCLK (Hz)         = 72000000
*                HCLK   (Hz)         = 72000000
*                AHB Prescaler       = 1
*                APB1 Prescaler      = 2
*                APB2 Prescaler      = 1
*                HSE Frequency (Hz)  = 80000000
*                HSE PREDIV1         = 1
*                PLLMUL              = 9
*                Flash Latency (WS)  = 2
*/

void SystemClock_Config(void) {
     RCC_ClkInitTypeDef clkinitstruct = {0};
     RCC_OscInitTypeDef oscinitstruct = {0};
     oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
     oscinitstruct.HSEState = RCC_HSE_ON;
     oscinitstruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
     oscinitstruct.PLL.PLLState = RCC_PLL_ON;
     oscinitstruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
     oscinitstruct.PLL.PLLMUL = RCC_PLL_MUL9;
     if (HAL_RCC_OscConfig(&oscinitstruct) != HAL_OK) {
          while(1);
     }
     clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
     clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
     clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
     clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1;
     clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2;
     if (HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2) != HAL_OK) {
          while(1);
     }
}

/**
* This function handles I2C event interrupt requests.
*/

void I2C1_ER_IRQHandler(void) {
     HAL_I2C_ER_IRQHandler(&I2cHandle);
}

/**
* This function handles I2C error interrupt requests.
*/

void I2C1_EV_IRQHandler(void) {
     HAL_I2C_EV_IRQHandler(&I2cHandle);
}

/**
* Blinks onboard LED to show board is starting.
*/

void Startup_Sequence(void) {
     int i;
       for(i=1;i<50; i++) {
         HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
         HAL_Delay(1000 * (1.0/i));
       }
     HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
}

/**
* Blinks onboard LED to show that code has errored.
*/

void Error_Handler(void) {
     while (1) {
          HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
          HAL_Delay(400);
     }
}

/**
* Waits until slave is ready to receive data and then sends data to slave.
* @param addr   [8 bit address of slave device]
* @param data   [Data to be sent to slave device]
* @param length [Length of data being sent in bytes]
*/

void i2c1_send_data(uint16_t addr, uint8_t* data, uint8_t length) {
    while (HAL_I2C_GetState(&I2cHandle) != HAL_I2C_STATE_READY){}
    while (HAL_I2C_Master_Transmit_IT(&I2cHandle, addr, data, length) != HAL_OK) {
        Error_Handler();
    }
}

/**
* Waits until slave is ready to transmit data and then receives data from slave
* @param addr   [8 bit address of slave device]
* @param data   [Pointer to where data will be stored]
* @param length [Length of data being received]
*/

void i2c1_receive_data(uint16_t addr, uint8_t* data, uint8_t length) {
    while (HAL_I2C_GetState(&I2cHandle) != HAL_I2C_STATE_READY) {}
    while (HAL_I2C_Master_Receive_IT(&I2cHandle, addr, data, length) != HAL_OK) {
        Error_Handler();
    }
}

I think my receive function is wrong because it is not acknowledging the data. How can I get it to acknowledge the data?

Outcomes