2017-09-16 09:17 PM
I have an STM32F401RE-Nucleo board and I have bought the mbed Application Shield to toy with the STM ecosystem.
Lately I have been trying to talk to the temperature sensor LM75B and I have achieved some success by being able to read the temperature register which is also the default register by using a call toHAL_I2C_Mem_Read andHAL_I2C_Mem_Read_IT. My problem is that I can't seem to be able to read the configuration register, the hysteresis register and the overtemperature shutdown register.
My code is this:
main.c
/* Includes ------------------------------------------------------------------*/
#include 'main.h'
#define I2C_ADDRESS 0x90
I2C_HandleTypeDef I2cHandle;
/* Buffer used for reception */
uint8_t aRxBuffer[512];
/* Private function prototypes -----------------------------------------------*/
static void SystemClock_Config(void);
static void Error_Handler(void);
int main(void)
{
volatile float temp = 0.0; /* Temperature */
volatile float thyst = 0.0; /* Hysteresis register default 75deg C */
volatile float tos = 0.0; /* Overtemperature shutdown default 80deg C */
HAL_Init();
/* Configure LED2 */
BSP_LED_Init(LED2);
/* Configure the System clock to 84 MHz */
SystemClock_Config();
/*##-1- Configure the I2C peripheral ######################################*/
I2cHandle.Instance = I2Cx;
I2cHandle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
I2cHandle.Init.ClockSpeed = 100000;
I2cHandle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
I2cHandle.Init.DutyCycle = I2C_DUTYCYCLE_16_9;
I2cHandle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
I2cHandle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
I2cHandle.Init.OwnAddress1 = 0;
I2cHandle.Init.OwnAddress2 = 0xFE;
if(HAL_I2C_Init(&I2cHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/* Infinite loop */
while (1)
{
/*##-4- Put I2C peripheral in reception process ############################*/
do
{
if(HAL_I2C_Mem_Read_IT(&I2cHandle, (uint16_t)I2C_ADDRESS, 0, I2C_MEMADD_SIZE_8BIT, (uint8_t *)&aRxBuffer[0], 8) != HAL_OK)
{
/* Error_Handler() function is called in case of error. */
Error_Handler();
}
/* When Acknowledge failure occurs (Slave don't acknowledge its address)
Master restarts communication */
}
while(HAL_I2C_GetError(&I2cHandle) == HAL_I2C_ERROR_AF);
while (HAL_I2C_GetState(&I2cHandle) != HAL_I2C_STATE_READY)
{
}
/* Convert register data to temperatures */
temp = 0.125*(aRxBuffer[0]*8.0+ (aRxBuffer[1]>>5));
thyst = 0.125*(aRxBuffer[4]*8.0+ (aRxBuffer[5]>>5));
tos = 0.125*(aRxBuffer[6]*8.0+ (aRxBuffer[7]>>5));
BSP_LED_Toggle(LED2);
HAL_Delay(500);
}
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
main.h
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
/* Includes ------------------------------------------------------------------*/
#include 'stm32f4xx_hal.h'
#include 'stm32f4xx_nucleo.h'
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* User can use this section to tailor I2Cx/I2Cx instance used and associated
resources */
/* Definition for I2Cx clock resources */
#define I2Cx I2C1
#define I2Cx_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE()
#define I2Cx_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define I2Cx_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define I2Cx_FORCE_RESET() __HAL_RCC_I2C1_FORCE_RESET()
#define I2Cx_RELEASE_RESET() __HAL_RCC_I2C1_RELEASE_RESET()
/* Definition for I2Cx Pins */
#define I2Cx_SCL_PIN GPIO_PIN_8
#define I2Cx_SCL_GPIO_PORT GPIOB
#define I2Cx_SCL_AF GPIO_AF4_I2C1
#define I2Cx_SDA_PIN GPIO_PIN_9
#define I2Cx_SDA_GPIO_PORT GPIOB
#define I2Cx_SDA_AF GPIO_AF4_I2C1
/* Definition for I2Cx's NVIC */
#define I2Cx_EV_IRQn I2C1_EV_IRQn
#define I2Cx_EV_IRQHandler I2C1_EV_IRQHandler
#define I2Cx_ER_IRQn I2C1_ER_IRQn
#define I2Cx_ER_IRQHandler I2C1_ER_IRQHandler
/* Size of Transmission buffer */
#define TXBUFFERSIZE (COUNTOF(aTxBuffer) - 1)
/* Size of Reception buffer */
#define RXBUFFERSIZE TXBUFFERSIZE
/* Exported macro ------------------------------------------------------------*/
#define COUNTOF(__BUFFER__) (sizeof(__BUFFER__) / sizeof(*(__BUFFER__)))
/* Exported functions ------------------------------------------------------- */
#endif /* __MAIN_H */
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
And the files stm32f4xx_hal_msp.c and stm32f4xx_it.c have the default structure.
For those of you too lazy to look into the datasheet
temp is in address 00
conf is in address 01
hyst temp in adress 02
and overshoot temp in address 03
So the expected temperatures reported should be room temperature in temp, 75 degrees C in hysteresis temperature and 80 degrees C for shutdown temperature as the last two are the default values of these registers.
The output that I get is room temperature (varying in steps of 0.125) for all three of them.
Can someone point out why that happens?
Datasheet link
https://www.nxp.com/docs/en/data-sheet/LM75B.pdf
Juice is in Chapter 7
#hal_i2c_mem_read #stm32f4 #nucleo #stm32f4-i2c-hal-driver #lm75b2017-09-16 09:30 PM
Ok I just found out why that happens and it seems to be partly because I misread the datasheet and partly because the HAL_I2C_Mem_Read function API is a bit misleading.
You can only read one register at a time so you would have to break this:
HAL_I2C_Mem_Read_IT(&I2cHandle, (uint16_t)I2C_ADDRESS, 0, I2C_MEMADD_SIZE_8BIT, (uint8_t *)&aRxBuffer[0], 8)
�?�?�?
into three function calls:
HAL_I2C_Mem_Read_IT(&I2cHandle, (uint16_t)I2C_ADDRESS, 0, I2C_MEMADD_SIZE_8BIT, (uint8_t *)&aRxBuffer[0], 2)
HAL_I2C_Mem_Read_IT(&I2cHandle, (uint16_t)I2C_ADDRESS, 2, I2C_MEMADD_SIZE_8BIT, (uint8_t *)&aRxBuffer[2], 2)
HAL_I2C_Mem_Read_IT(&I2cHandle, (uint16_t)I2C_ADDRESS, 3, I2C_MEMADD_SIZE_8BIT, (uint8_t *)&aRxBuffer[4], 2)�?�?�?�?�?�?�?�?�?�?�?�?
So the size of bytes in the end IMO is a bit misleading. I was under the impression that it would read 8 bytes from address 0 which would return temp, conf, hyst, tos instead what you get is temp, temp, temp, temp.
So if you want to read multiple registers the only option is to use one function call for each register. At least that's the only obvious solution to me.
Can someone from STM propose a better one?
P.S. Another bit which I found confusing is theMemAddSize argument because it is not clear whether it means that the size is measured in bytes or bits.