I am new I2C communication. I examined some running code. And I used function their used. But I can't get any data. I wonder if I2C have to do initial config? Where is the problem. This is function I wrote:
void GetI2CAccelerometer(uint8_t slaveAddress,uint8_t accelData[6])
{
// slaveAddress=0x68 (default address is written in datasheet)
HAL_I2C_Master_Transmit(&hi2c1,slaveAddress<<1,1,0x3B,1,200);
HAL_I2C_Master_Receive(&hi2c1,slaveAddress<<1,accelData,6,200);
HAL_I2C_Mem_Read(&hi2c1,(slaveAddress<<1)+1,0x3B,1,accelData,1,200);
// i tried this function too but not working
}
I created this project with CubeMX. This is initial I2C config and also GPIO_A clock line is activated in another function which I did not write:
static void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 208;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
First of all, better use DMA or IT data exchange. Polling is not good, but ok for testing.
You must put pointers to data, not the data itself. The good practice is something like this:
void GetI2CAccelerometer(I2C_HandleTypeDef * hi2c, uint8_t slaveAddress, uint8_t * accelData, size_t size) {
uint8_t request = 0x3B;
// slaveAddress=0x68 (default address is written in datasheet)
// HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
while (HAL_I2C_Master_Transmit(hi2c, slaveAddress << 1, (uint8_t*)request, 1, 200) != HAL_OK) {
// Use FreeRTOS vTaskDelay(1) and/or check errors here
// And check timeout or you will hang over here
}
//HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
while (HAL_I2C_Master_Receive(hi2c, slaveAddress << 1, accelData, size, 200) != HAL_OK) {
// Use FreeRTOS vTaskDelay(1) and/or check errors here
// And check timeout or you will hang over here
}
while (HAL_I2C_GetState(hi2c) != HAL_I2C_STATE_READY) {
// Use FreeRTOS vTaskDelay(1) and/or check errors here
// And check timeout or you will hang over here
}
}
And then request data by function:
uint8_t accelData[6];
GetI2CAccelerometer(&hi2c1, 0x68, accelData, 6);
Thats ok for testing, but bad for production. Get the data and then rewrite to use I2C DMA or IT. Check errors at I2C bus and make some enum to return errors/states from function.
Related
I tried to learn the CMSIS driver in I2C. I have STM32F407VGT6 and EEPROM at24c256 as test hardware. First, create the I2C environment with CubeMX to config the I2C.
https://imgur.com/CbroTeo
https://imgur.com/nCP5eFt
then I followed the arm example from the arm-cmsis driver website.
https://arm-software.github.io/CMSIS_5/Driver/html/group__i2c__interface__gr.html
#include "Driver_I2C.h"
#define EEPROM_I2C_ADDR 0xA0 /* EEPROM I2C address */
/* I2C driver instance */
extern ARM_DRIVER_I2C Driver_I2C1;
static ARM_DRIVER_I2C *I2Cdrv = &Driver_I2C1;
static volatile uint32_t I2C_Event;
/* I2C Signal Event function callback */
void I2C_SignalEvent (uint32_t event) {
/* Save received events */
I2C_Event |= event;
/* Optionally, user can define specific actions for an event */
if (event & ARM_I2C_EVENT_TRANSFER_INCOMPLETE) {
/* Less data was transferred than requested */
}
if (event & ARM_I2C_EVENT_TRANSFER_DONE) {
/* Transfer or receive is finished */
}
if (event & ARM_I2C_EVENT_ADDRESS_NACK) {
/* Slave address was not acknowledged */
}
if (event & ARM_I2C_EVENT_ARBITRATION_LOST) {
/* Master lost bus arbitration */
}
if (event & ARM_I2C_EVENT_BUS_ERROR) {
/* Invalid start/stop position detected */
}
if (event & ARM_I2C_EVENT_BUS_CLEAR) {
/* Bus clear operation completed */
}
if (event & ARM_I2C_EVENT_GENERAL_CALL) {
/* Slave was addressed with a general call address */
}
if (event & ARM_I2C_EVENT_SLAVE_RECEIVE) {
/* Slave addressed as receiver but SlaveReceive operation is not started */
}
if (event & ARM_I2C_EVENT_SLAVE_TRANSMIT) {
/* Slave addressed as transmitter but SlaveTransmit operation is not started */
}
}
/* Read I2C connected EEPROM (event driven example) */
int32_t EEPROM_Read_Event (uint16_t addr, uint8_t *buf, uint32_t len) {
uint8_t a[2];
a[0] = (uint8_t)(addr >> 8);
a[1] = (uint8_t)(addr & 0xFF);
/* Clear event flags before new transfer */
I2C_Event = 0U;
I2Cdrv->MasterTransmit (EEPROM_I2C_ADDR, a, 2, true);
/* Wait until transfer completed */
while ((I2C_Event & ARM_I2C_EVENT_TRANSFER_DONE) == 0U);
/* Check if all data transferred */
if ((I2C_Event & ARM_I2C_EVENT_TRANSFER_INCOMPLETE) != 0U) return -1;
/* Clear event flags before new transfer */
I2C_Event = 0U;
I2Cdrv->MasterReceive (EEPROM_I2C_ADDR, buf, len, false);
/* Wait until transfer completed */
while ((I2C_Event & ARM_I2C_EVENT_TRANSFER_DONE) == 0U);
/* Check if all data transferred */
if ((I2C_Event & ARM_I2C_EVENT_TRANSFER_INCOMPLETE) != 0U) return -1;
return 0;
}
/* Read I2C connected EEPROM (pooling example) */
int32_t EEPROM_Read_Pool (uint16_t addr, uint8_t *buf, uint32_t len) {
uint8_t a[2];
a[0] = (uint8_t)(addr >> 8);
a[1] = (uint8_t)(addr & 0xFF);
I2Cdrv->MasterTransmit (EEPROM_I2C_ADDR, a, 2, true);
/* Wait until transfer completed */
while (I2Cdrv->GetStatus().busy);
/* Check if all data transferred */
if (I2Cdrv->GetDataCount () != len) return -1;
I2Cdrv->MasterReceive (EEPROM_I2C_ADDR, buf, len, false);
/* Wait until transfer completed */
while (I2Cdrv->GetStatus().busy);
/* Check if all data transferred */
if (I2Cdrv->GetDataCount () != len) return -1;
return 0;
}
/* Initialize I2C connected EEPROM */
int32_t EEPROM_Initialize (bool pooling) {
int32_t status;
uint8_t val;
if (pooling == true) {
I2Cdrv->Initialize (NULL);
} else {
I2Cdrv->Initialize (I2C_SignalEvent);
}
I2Cdrv->PowerControl (ARM_POWER_FULL);
I2Cdrv->Control (ARM_I2C_BUS_SPEED, ARM_I2C_BUS_SPEED_FAST);
I2Cdrv->Control (ARM_I2C_BUS_CLEAR, 0);
/* Check if EEPROM can be accessed */
if (pooling == true) {
status = EEPROM_Read_Pool (0x00, &val, 1);
} else {
status = EEPROM_Read_Event (0x00, &val, 1);
}
return (status);
}
above was the code example from cmsis-driver website. I have modified the EEPROM_I2C_ADDR to 0xA0(for AT24C256 EEPROM).
then I try to run main() with function
EEPROM_Initialize(true)
then this function will get into EEPROM_Read_Pool()
but the test always stuck in
while (I2Cdrv->GetStatus().busy);
after I2Cdrv->MasterTransmit (EEPROM_I2C_ADDR, a, 2, true);。
I have tried
use HAL library to run MEM_Write, MEM_Read with the EEPROM, and make sure the EEPROM could work.
HAL_I2C_Mem_Write(&hi2c1, EEPROM_ADDRESS, 0, 0xff, &data_to_write, 1,10);
HAL_Delay(10);
uint8_t data_read = 60;
HAL_I2C_Mem_Read(&hi2c1,EEPROM_ADDRESS,0,0xff,&data_to_read,1,1);
I have checked the return value of all below
I2Cdrv->PowerControl (ARM_POWER_FULL);
I2Cdrv->Control (ARM_I2C_BUS_SPEED, ARM_I2C_BUS_SPEED_FAST);
I2Cdrv->Control (ARM_I2C_BUS_CLEAR, 0);
I2Cdrv->MasterTransmit (EEPROM_I2C_ADDR, a, 2, true);
all the return value are 0x00000000(seems running ok).But still have no idea why the status is always busy.
I have checked that it has no chance to get into the
I2C_EV_IRQHandler or I2C_ER_IRQHandlerin debug mode to change the status or increase the TX count.
The goal is to read multiple ADC channels by polling. It does not need to be fast - the idea is to read the voltages from different batteries that are attached. I have a STM32L071 microcontroller. The programming is a bit different compared to the STM32F0 model. I am using platformio.
I found already very helpful information here:
Individually read distinct inputs with STM32F0 ADC
https://controllerstech.com/stm32-adc-multiple-channels/
https://deepbluembedded.com/stm32-adc-tutorial-complete-guide-with-examples/
However, unfortunately I cannot read out multiple channels. The problems are probably related to HAL_ADC_Init and HAL_ADC_ConfigChannel.
Here is a minimal code example:
#include <Arduino.h>
#include <STM32IntRef.h>
uint32_t a1=0, a2=0;
#define HAL_ADC_MODULE_ENABLED
ADC_HandleTypeDef hadc1;
void displaying(){
Serial.println("values:");
Serial.println("-------");
Serial.print("ch1 - ");
Serial.println(a1);
Serial.print("ch2 - ");
Serial.println(a2);
Serial.println("");
}
void config_ext_channel_ADC(uint32_t channel, bool val) {
hadc1.Instance = ADC1;
hadc1.Init.SamplingTime = ADC_SAMPLETIME_79CYCLES_5;
HAL_ADC_Init(&hadc1);
ADC_ChannelConfTypeDef sConfig;
sConfig.Channel = channel;
if (val == true) {
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
} else {
sConfig.Rank = ADC_RANK_NONE;
}
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
Serial.println("Error ADC Config Channel");
//Error_Handler();
}
}
uint32_t r_single_ext_channel_ADC(uint32_t channel) {
/* read the ADC and output result */
uint32_t digital_result;
config_ext_channel_ADC(channel, true);
HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 1000);
digital_result = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
config_ext_channel_ADC(channel, false);
return digital_result;
}
void readBat() {
/* read voltages */
a1 = r_single_ext_channel_ADC(1);
a2 = r_single_ext_channel_ADC(PA2);
}
void setup() {
// put your setup code here, to run once:
// Serial monitor
Serial.begin(9600);
Serial.println(F("Starting now"));
// initialize pins for ADC
analogReadResolution(ADC_RESOLUTION);
pinMode(PA1, INPUT);
//pinMode(BATTERY_SENSE_PIN2, INPUT);
pinMode(PA2, INPUT_ANALOG);
}
void loop() {
// put your main code here, to run repeatedly:
readBat();
displaying();
delay(2000);
}
The output is:
values:
-------
ch1 - 0
ch2 - 140
Sounds reasonable, but applying some voltages at the pins does not change the values.
Could somebody please provide me some advice, ideas?
Okay, in the meantime I found the problem. The software is fine; I took the Arduino framework and used analogRead().
I needed to clean all the solder flux from the PCB which caused some contacts between the pins.
Moreover, if one wants to use address the HAL directly, one should set the ClockDivider such that the ADC samples below 1 MHz.
Code to read different ADC channels (here ADC2 with 2 channels) separetly (Generated By CubeMX):
Note: We have to use ScanConvMode plus DiscontinuousConvMode and NO ContinuousConvMode.
/* ADC2 init function */
void MX_ADC2_Init(void)
{
/* USER CODE BEGIN ADC2_Init 0 */
/* USER CODE END ADC2_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC2_Init 1 */
/* USER CODE END ADC2_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc2.Instance = ADC2;
hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc2.Init.Resolution = ADC_RESOLUTION_12B;
hadc2.Init.ScanConvMode = ENABLE;
hadc2.Init.ContinuousConvMode = DISABLE;
hadc2.Init.DiscontinuousConvMode = ENABLE;
hadc2.Init.NbrOfDiscConversion = 1;
hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.NbrOfConversion = 2;
hadc2.Init.DMAContinuousRequests = DISABLE;
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc2) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_9;
sConfig.Rank = 2;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC2_Init 2 */
/* USER CODE END ADC2_Init 2 */
}
Now, to read:
void readChannel(){
//read the next channel
HAL_ADC_Start(&hadc2);
uint8_t ret = HAL_ADC_PollForConversion(&hadc2, 1000 /*timeout*/);
uint16_t value = HAL_ADC_GetValue(hadc);
printf("HAL_ADC_PollForConversion status: %d, VALLLL: %d\n", ret, value);
}
int main(){
while(1){
//Automatically read the first channel (channel 8):
readChannel();
HAL_Delay(100);
//Automatically read the second channel (channel 9):
readChannel();
HAL_Delay(100);
}
}
Did you miss to set the io to analog in mode? It should be something like this somewhere (usually in your hal msp file, adc_init func).
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
edit => you missed it for ch1
analogReadResolution(ADC_RESOLUTION);
pinMode(PA1, INPUT);
//pinMode(BATTERY_SENSE_PIN2, INPUT);
pinMode(PA2, INPUT_ANALOG);
It should be the same as PA2, input is "digital mode".
In a STM32G4, I was able to setup the DAC DMA such that I could use a regular variable (ie. a uint8_t array). However, when I tried porting my code over to an H723, the DAC DMA would not work unless it's with a constant variable (ie. a const uint8_t array) that is set before runtime. My application requires runtime changes to the array. A pointer initialization of the array does not seem to work. I was wondering if there is a way to remedy this? Am I stuck with the constant variable? Thank you!
EDIT1: Current Setup of DAC DMA and TIMER
static void MX_DAC1_Init(void){
DAC_ChannelConfTypeDef sConfig = {0};
hdac1.Instance = DAC1;
if (HAL_DAC_Init(&hdac1) != HAL_OK){
Error_Handler();
}
sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
sConfig.DAC_Trigger = DAC_TRIGGER_T15_TRGO;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;
sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_ENABLE;
sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;
if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
}
Timer15 Config:
static void MX_TIM15_Init(void)
{ TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim15.Instance = TIM15;
htim15.Init.Prescaler = 55-1;
htim15.Init.CounterMode = TIM_COUNTERMODE_UP;
htim15.Init.Period = 10-1;
htim15.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim15.Init.RepetitionCounter = 0;
htim15.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim15) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim15, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim15, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
DMA Config:
static void MX_DMA_Init(void){
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
/* DMAMUX1_OVR_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMAMUX1_OVR_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMAMUX1_OVR_IRQn);
}
in the main function:
int main(void){
MX_DAC1_Init();
MX_TIM15_Init();
MX_OPAMP2_Init();
/* USER CODE BEGIN 2 */
set_sine(dac_data1, NUM_DAC_POINTS) //Set a max amplitude uniformly over number of points, dac_data is initialized as uint8_t dac_data1[NUM_DAC_POINTS];
HAL_TIM_Base_Start(&htim15); //Start the timer for DAC DMA Transfer
HAL_DAC_Init(&hdac1);
(HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_2, (uint32_t *)dac_data1, NUM_DAC_POINTS, DAC_ALIGN_8B_R);
}
This setup does not work, but just by initialzing dac_data1 as const uint8_t and predefining it, the DMA works.
Ok, Thanks to Tom V for the insight on the Different Memory Banks. In my case, dac_data1 is placed on RAM, also known as DTCMRAM on the reference manual. DTCMRAM is not accessible to DMA but is chosen to be the default memory location for runtime operations on the H7. A modification in the linker files (In my case, both ..._FLASH.ld and ..._RAM.ld) were needed. I changed the .bss, .data and ._user_heap_stack memory location from RAM to RAM_D1. This was taken directly from: https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices
I am interfacing AT24C02 external eeprom using stm32f401 nucleo. I am facing few issues.
Lets consider some address
/* 24c02 Device Address */
#define EEPROM_ADDRESS (uint8_t)0xA0
/*Demo addr*/
#define DEMO_BYTE_ADDR (uint16_t)0x01
#define DEMO_WORD_ADDR (uint16_t)0x02
#define DEMO_FLOAT_ADDR (uint16_t)0x06
#define DEMO_STRING_ADDR (uint16_t)0x0A
1. Writing and reading simultaneously.
I am able to write and read data to and from eeprom simultaneously.
/*Writing Byte*/
uint8_t byte;
eep_write_byte(DEMO_BYTE_ADDR, 50);
eep_read_byte(DEMO_BYTE_ADDR, &byte);
/*Wrinting word*/
uint32_t word;
eep_write_word(DEMO_WORD_ADDR, 123456789);
word = eep_read_word(DEMO_WORD_ADDR);
/*Writing float*/
float fData;
eep_write_float(DEMO_FLOAT_ADDR, 9876.54);
fData = eep_read_float(DEMO_FLOAT_ADDR);
This code works fine. Below is the snapshot of output.
2. Problems with writing string
After the above portion of code i have written some lines to write string and read string. As you can see in output buffer dest contains some value.
uint8_t dest[50] = {0};
eep_write_string(DEMO_STRING_ADDR, (uint8_t*)"Hello World!", strlen("Hello World!"));
eep_read_string(DEMO_STRING_ADDR, dest, strlen("Hello World!"));
3. After writing all these values the reading shows corrupted data
After the above portion of the code if i read back all the addresses i have wrote gives me corrupted data.
eep_read_byte(DEMO_BYTE_ADDR, &byte);
word = eep_read_word(DEMO_WORD_ADDR);
fData = eep_read_float(DEMO_FLOAT_ADDR);
eep_read_string(DEMO_STRING_ADDR, dest, strlen("Hello World!"));
Below is the snapshot of out for this code.
As you can see all the data is now corrupted.
you can find eeprom.c from this link https://pastebin.com/2vYWYhnw or just scroll below.
/*
* eeprom.c
*
* Created on: 04-Jan-2021
* Author: DEVJEET MANDAL
*/
#include "i2c.h"
#include "eeprom.h"
#include "stdio.h"
#include "stdlib.h"
/* Low Level function */
void eep_small_delay(void) {
for (uint32_t i = 0; i < 65535; i++)
__asm__("NOP");
}
void i2c_error(void) {
HAL_I2C_DeInit(&hi2c1); //De-init i2c bus
__asm__("NOP");
HAL_I2C_Init(&hi2c1); //re-init i2c bus
__asm__("NOP");
}
eep_status_t i2c_write(uint16_t u8_reg_addr, uint8_t *u8_data, uint16_t len) {
HAL_StatusTypeDef xStatus = HAL_ERROR;
xStatus = HAL_I2C_Mem_Write(&hi2c1, EEPROM_ADDRESS, u8_reg_addr, I2C_MEMADD_SIZE_16BIT, u8_data, len, 100);
HAL_Delay(5);
if (xStatus != HAL_OK) {i2c_error();}
return xStatus;
}
eep_status_t i2c_read(uint16_t u8_reg_addr, uint8_t *u8_data, uint16_t len) {
HAL_StatusTypeDef xStatus = HAL_ERROR;
xStatus = HAL_I2C_Mem_Read(&hi2c1, EEPROM_ADDRESS, u8_reg_addr, I2C_MEMADD_SIZE_16BIT, u8_data, len, 100);
eep_small_delay();
if (xStatus != HAL_OK) {i2c_error();}
return xStatus;
}
/* High Level Functions */
eep_status_t eep_write_byte(uint16_t u8_reg_addr, uint8_t u8_data) {
return i2c_write(u8_reg_addr, &u8_data, 1);
}
eep_status_t eep_read_byte(uint16_t u8_reg_addr, uint8_t *u8_data) {
return i2c_read(u8_reg_addr, u8_data, 1);
}
eep_status_t eep_is_data_avaiable(void) {
eep_status_t xStatus = EEP_ERROR;
uint8_t data = 0;
eep_read_byte(EEPROM_DATA_AVAILABLE_ADDR, &data);
if (data == 0) {xStatus = EEP_ERROR;}
else if (data == 1) {xStatus = EEP_OK;}
else {xStatus = EEP_ERROR;}
return xStatus;
}
eep_status_t eep_set_data_available(uint8_t val) {
return eep_write_byte(EEPROM_DATA_AVAILABLE_ADDR, val);
}
eep_status_t eep_write_word(uint16_t reg_addr, uint32_t value) {
uint8_t val_byte[4] = {0};
val_byte[0] = (value >> 24) & 0xFF;
val_byte[1] = (value >> 16) & 0xFF;
val_byte[2] = (value >> 8) & 0xFF;
val_byte[3] = (value >> 0) & 0xFF;
return i2c_write(reg_addr, val_byte, 4);
}
eep_status_t eep_write_float(uint16_t reg_addr, float value) {
union FtoHex{
float fval;
uint32_t hval;
}float_to_hex;
float_to_hex.fval = value;
return eep_write_word(reg_addr, float_to_hex.hval);
}
uint32_t eep_read_word(uint16_t reg_addr) {
uint8_t val_buff[4] = {0};
i2c_read(reg_addr, val_buff, 4);
return ((val_buff[0] << 24) | (val_buff[1] << 16) | (val_buff[2] << 8) | (val_buff[3] << 0));
}
float eep_read_float(uint8_t reg_addr) {
union FtoHex{
float fval;
uint32_t hval;
}float_to_hex;
float_to_hex.hval = eep_read_word(reg_addr);
return float_to_hex.fval;
}
void eep_write_string(uint16_t reg_addr, uint8_t *src, uint16_t len) {
i2c_write(reg_addr, src, len);
}
void eep_read_string(uint16_t reg_addr, uint8_t *dest, uint16_t len) {
i2c_read(reg_addr, dest, len);
}
//---------------------------------------------------------------------
Almost forgot to mention i m running I2C #400Khz. Though i have tried 100KHz which results same.
Below is the HAL generated I2C init.
/* I2C1 init function */
void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 400000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
Now the question is why this problem. Basically the HAL should take care of all the situation and i will just send data to it. Any help will be appreciated.
Regards.
You missed that AT24C02 is organized in 16 byte (write) pages.
The corruption is caused by rollover/wrap # offset 0x0F when writing the string starting # offset 0x0A.
See the data sheet for details.
i want to read touch activity from the touchscreen.If i touch, i want to led blink. Some my definitions in below code but generally i want to get my activity with i2c
Some definitions:
uint8_t deviceaddr;
static uint32_t touch_i2c_read(uint8_t DeviceAddr, uint8_t RegAddr, uint8_t *pBuffer, uint16_t len);
static const int I2C_TIMEOUT = 65536;
unsigned char i2c_buffer[256];
uint32_t res;
This is my i2c read code:
static uint32_t touch_i2c_read(uint8_t DeviceAddr, uint8_t RegAddr, uint8_t *pBuffer, uint16_t len)
{ //uint8_t deviceaddr ,0x00,(uint8_t *)&buf, sizeof(buf)
uint32_t timeout = I2C_TIMEOUT;
while (I2C_GetFlagStatus(I2C1, I2C_ISR_BUSY) != RESET)
{
if ((timeout--) == 0)
return 0;
}
I2C_TransferHandling(I2C1, DeviceAddr << 1, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
/* !!! Wait until TXIS flag is set !!! */
timeout = I2C_TIMEOUT;
while (I2C_GetFlagStatus(I2C1, I2C_ISR_TXIS) == RESET)
{
if ((timeout--) == 0)
return 0;
}
}
This is my settings
void configure_interrupt_pins()
{
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
/*ENABLE CLOCK FOR GPIOX*/
RCC_APB1PeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
// ENABLE CLOCK FOR SYSCFG
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
//SET PIN AS INPUT
// init_pin(EX_NCVIC_PORT, EX_NCVIC_Pin, GPIO_MODE_INPUT, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_UP);
//TELL THE SYSTEM THAT YOU WILL USE PXX FOR EXTI_LineX
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOx, EXTI_PinSourcex);
//CONFIGIRATION of exti
EXTI_InitStruct.EXTI_Line = EXTI_Linex; //pxx connect to line x
EXTI_InitStruct.EXTI_LineCmd = ENABLE; //enable interrupt
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; //interrupt mode
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //triggers on rising and failing edge
EXTI_Init(&EXTI_InitStruct); //add to exti
//CONFIGURATION of nvic
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
This is my interrupt
void EXTI0_IRQHandler(void)
{
if (EXTI_GetITStatus((EXTI_Line0) != RESET))
{
res = touch_i2c_read(0x42, 0x00, i2c_buffer, 22);
printf("deneme");
if (!res)
{
GPIO_SetBits(GPIOE, GPIO_Pin_13);
}
else
{
GPIO_SetBits(GPIOE, GPIO_Pin_13);
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
But my code not working. Stm32 dont understand touch activity how can i solve this.
Edit i change line 1 every external interupts but i have res value 0 how can i fix this it must be different 0
Using a while() loop in an interrupt will cause problems, because the controller will never exit the loop. Try to use your i2c read Function in main() (with other words, a not-interrupt-context) and look if it works there.
I solved this error.
I hadn't any signal pb7 and pb6 so i changed codes as below:
// enable APB1 peripheral clock for I2C1
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
// enable clock for SCL and SDA pins
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
And then,
Device adress of the FT6236 was mising. it is not include at datasheet so i used debugging. I found the device adress which is the (0x32). And than my code working succesfully.