I have been trying to write a byte to the EEPROM 23LC32A through I2C protocol. I am using uvision 5 Keil to code my program.
When I run my code in the Termite.exe terminal window, the output seems to indicate that read function is executing. It returns 255, which is the default value of a cleared EEPROM. So the thing is that the writing of the data is not taking place.
I have configured and coded the control registers correctly as per the datasheet. What could have possibly gone wrong? And also please do help with me page writing of EEPROM too. Here is my code below:
void write8eeprom(uint8_t addr, uint8_t reghigh, uint8_t reglow, uint8_t value)
{
uint8_t bytes [3];
bytes[0] = reghigh;
bytes[1] = reglow;
bytes[2] = value;
bool success = twi_master_transfer(addr, (uint8_t*) &bytes, sizeof(bytes), TWI_ISSUE_STOP);
}
uint8_t read8(uint8_t addr, uint8_t reg)
{
uint8_t value;
uint8_t bytes [1];
bytes[0] = reg;
uint8_t regValue[1] ;
twi_master_transfer(addr, (uint8_t*) &bytes, sizeof(bytes), TWI_DONT_ISSUE_STOP);
twi_master_transfer(addr|TWI_READ_BIT, (uint8_t*) ®Value, sizeof(regValue), TWI_ISSUE_STOP);
value = regValue[0] ;
return value;
}
void eeprom_write()
{
uint8_t value;
value = 1;
write8eeprom(160, 0x1000, 0x0001, value);
printf("Data %d is written\n", value);
}
void eeprom_read()
{
uint8_t value;
value = read8(160, 0x00000001);
printf("The data %d is read\n", value);
}
int main(void)
{
nrf_drv_clock_lfclk_request();
timers_init();
application_timers_start();
nrf_delay_ms(2000);
uart_config();
gpio_config();
bool tt= twi_master_init ( ) ;
nrf_delay_ms(2000);
printf("\n\r I2C \n\r");
eeprom_write();
nrf_delay_ms(1000);
eeprom_read();
for(;;)
{
__WFE();
}
}
Related
This is the how I'm trying to write to flash
Basically I pass my uint16_t array to a function called FLASH_WriteA which accepts the array, the destination array or the location and the length
void FLASH_WriteA(uint16_t * src, uint16_t * dest, uint16_t length_16)
{
uint32_t firstAddress= FLASH_GetFirstAddress((uint32_t)dest, PAGE_SIZE_BYTES); // gets the first address of that page
uint32_t offset = ((uint32_t)dest - seg) / 2; // offset is in words
HAL_FLASH_Unlock();
Flash_Erase_Page((uint16_t*)seg); // calls the page erase function
FLASH_Write_HAL((uint32_t *)&flashBuffer, (uint16_t*)seg, FLASH_TABLE_SIZE_BYTES); //FLASH_TABLE_SIZE_BYTES = 256 = size of array
HAL_FLASH_Lock();
}
HAL_StatusTypeDef Flash_Erase_Page(uint16_t* seg){//, uint16_t length){
//uint16_t pages = (length/page_size) + (int)((length % page_size) != 0);
uint32_t pages = 2; // page size for STM32L053 = 128 bytes
FLASH_EraseInitTypeDef EraseInitStruct;
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.PageAddress = seg;
EraseInitStruct.NbPages = pages;
uint32_t PageError;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK) //Erase the Page Before a Write Operation
{
return HAL_ERROR;
}
}
void FLASH_Write_HAL(uint32_t *p_source, uint16_t* seg, uint16_t length)
{
uint32_t varToPass;
uint16_t wordcount=0;
int i;
for (i=0; i<length; i++){
varToPass = p_source[i] ;
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,seg+wordcount,varToPass);
wordcount += 4;
// if (wordcount>=256){
// break;
// }
}
}
I am trying to implement a driver for a sensor(ST-VL53L5CX) on an AVR MCU (AVR128DB48).
The driver comes prewritten, with a few I2C functions for the user to fill in
(So the sensor can be implemented on different platforms).
The driver is made up of multiple c files. API.c, API.h, Buffers.h, Platform.c and Platform.h.
The firmware for the sensor is stored in the Buffers.h file as an array. e.g:
const uint8_t Sensor_Firmware[] = {0x05,...,0x01};
This needs to be written to the sensor.
To do this, I call a function I have written to write multiple bytes to the I2C line:
uint8_t WrMulti(VL53L5CX_Platform *p_platform,uint16_t
RegisterAdress,uint8_t *p_values,uint32_t size)
{
uint8_t count = 0;
uint32_t new_size = size + 2;
//Split Register address into 2 bytes
uint8_t temp0 = (uint8_t)((RegisterAdress & 0xFF00)>> 8);
uint8_t temp1 = (uint8_t)(RegisterAdress & 0x00FF);
//Create new array to hold Register Address and p_values
uint8_t temp_array[new_size] ;
for (int i = 0; i <new_size; i++)
{
temp_array[i] = 0;
}
//Fill temp_array with register address and p_values
temp_array[0] = temp0;
temp_array[1] = temp1;
for (int i = 2; i < (new_size); i++ )
{
temp_array[i] = p_values[count];
count++;
}
//I2C
uint8_t status = 255;
while(!I2C0_Open(p_platform->address)); // sit here until we get the bus..
I2C0_SetBuffer(temp_array,new_size);
I2C0_SetAddressNackCallback(I2C0_SetRestartWriteCallback,NULL); //NACK polling?
I2C0_MasterWrite();
while(I2C0_BUSY == I2C0_Close()); // sit here until finished.
/* This function returns 0 if OK */
status = 0;
return status;
}
This works when sending an array that is located in my main.c file.
e.g:
//buffer.h
const uint8_t Sensor_Firmware[] = {0x05,...,0x01};
//End buffer.h
.
//main.c
void main (void)
{
uint8_t I2C_address = 0x01;
uint8_t I2C_reg = 0x01;
uint32_t size = 16;
uint8_t temp_array[size];
for (int i = 0; i <size; i++)
{
temp_array[i] = Sensor_Firmware[i];
}
WrMulti(I2C_address, I2C_reg, &temp_array[0], size);
While(1)
{
;
}
}
//End main.c
It also work when passing an array from the .h file without the 'const' key word.
e.g:
//buffer.h
uint8_t Sensor_Firmware[] = {0x05,...,0x01};
//End buffer.h
.
//main.c
void main (void)
{
uint8_t I2C_address = 0x01;
uint8_t I2C_reg = 0x01;
uint32_t size = 16;
uint8_t temp_array[size];
WrMulti(I2C_address, I2C_reg, &Sensor_Firmware[0], size);
While(1)
{
;
}
}
//End main.c
It does not when I pass the 'Sensor_Firmwware[]' array (with the const key word) from the .h file to 'WrMulti'. It just ends up sending '0x00' for every byte that comes from 'Sensor_Firmware'.
Does anyone know why this is might be?
Kind regards
Hi I’m a student Electronics-ICT and I’m having some trouble with a I2C project. I’m using FreeRTOS as a scheduler. To pass data between tasks I use the BaseType_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait); method that requires a item (in my case a struct). I have 3 struct types, 1 is the mainframe that has a payload field, the second one is a payload request (C-APDU format) and the last struct is a respond payload (R-APDU format).
Below a example of my structs.
// mainframe I2C
typedef struct I2CMainFrame
{
//RF or I2C host to M24SR64-Y:
//C-APDU M24SR64-Y to RF or I2C host: R-APDU
uint8_t DID;
uint8_t PCB; // PCB field
void *Payload; // Payload
uint8_t CRC1; // 2 CRC bytes
uint8_t CRC2;
} I2CMainFrame_t;
// payload request
typedef struct PayloadSend
{
uint8_t CLA; // Class byte 0x00: standard command 0xA2: ST comman
uint8_t INS; // Instruction byte
uint8_t P1; // Param Byte 1
uint8_t P2; // Param Byte 2
uint8_t LC; // Number of bytes of the Data field
uint8_t *Data; // Data bytes
uint8_t Le; // Number of bytes to be read in the M24SR64-Y memory
} PayloadSend_t;
// payload response
typedef struct PayloadGet
{
uint8_t *Data; // Pointer to data
uint8_t SW1; // status byte 1
uint8_t SW2; // status byte 2
} PayloadGet_t;
The problem is when i want to acces the data.
I need to pass a pointer to a methode that writes the data byte by byte on the I2C bus or that can calculate the CRC value
for example:
void CalculateCRC(uint8_t *data, size_t szLen, uint8_t *outputBuffer);
void WriteDataOnI2CBus(uint8_t *data, size_t szLen);
Is it posible to do something like this? I Tried the following code:
I2C UART task file simplified
I2CMainFrame_t mainframe;
PayloadSend_t payload;
void rtosUartTask(void)
{
//Fill payloaddata
uint8 data[] = {0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01};
payload.CLA = 0x00; payload.INS = 0xA4; payload.P1 = 0x04;
payload.P2 = 0x00; payload.LC = 0x07;
payload.Data = data; payload.Le = 0x00;
//fill mainframe data
mainframe.DID = 0xAC; mainframe.PCB = 0x02;
mainframe.Payload = &payload;
//methode for passing struct to I2C task
xQueueSend(I2CQueue, &mainframe,0);
}
I2C UART task file simplified
I2CMainFrame_t mainframe;
void rtosUartTask(void)
{
//Task manager starts this method when there is a item in the queue
xQueueReceive(I2CQueue, &mainframe, portMAX_DELAY);
//This doesnt work
uint8_t *pointerToStructMembers = &mainframe;
WriteDataOnI2CBus(pointerToStructMembers, sizeof(mainframe));
}
Am I looking in the right direction here or should I try another approach?
uint8_t *pointerToStructMembers = &mainframe;
You cannot use typecast since I2CMainFrame contains pointer member void *Payload.
What you can try is serialize the mainframe as below.
Declare an array of uint8_t then individually copy the contents to it.
uint8_t bufferedStructMembers[sizeof(I2CMainFrame_t) + sizeof (PayloadSend_t) + ((PayloadSend_t *)(mainframe.Payload))->LC];
bufferedStructMembers[0] = mainframe.DID;
bufferedStructMembers[1] = mainframe.PCB;
bufferedStructMembers[2] = ((PayloadSend_t *)(mainframe.Payload))->CLA;
bufferedStructMembers[3] = ((PayloadSend_t *)(mainframe.Payload))->INS;
bufferedStructMembers[4] = ((PayloadSend_t *)(mainframe.Payload))->P1;
bufferedStructMembers[5] = ((PayloadSend_t *)(mainframe.Payload))->P2;
bufferedStructMembers[6] = ((PayloadSend_t *)(mainframe.Payload))->LC;
memcpy(&bufferedStructMembers[7], ((PayloadSend_t *)(mainframe.Payload))->Data, ((PayloadSend_t *)(mainframe.Payload))->LC);
bufferedStructMembers[((PayloadSend_t *)(mainframe.Payload))->LC+7] = mainframe.Le;
bufferedStructMembers[((PayloadSend_t *)(mainframe.Payload))->LC+8] = mainframe.CRC1; // 2 CRC bytes
bufferedStructMembers[((PayloadSend_t *)(mainframe.Payload))->LC+9] = mainframe.CRC2;
WriteDataOnI2CBus(bufferedStructMembers, sizeof(mainframe));
I am working with MSP430 with FRAM Controller. And I Have to write a data from buffer over FRAM Location.
I have gone through bundled example of writing to FRAM.
unsigned long *FRAM_write_ptr;
unsigned long data;
#define FRAM_TEST_START 0xD000
data = 0x00010001;
void main
{
while(1)
{
data += 0x00010001;
FRAM_write_ptr = (unsigned long *)FRAM_TEST_START;
FRAMWrite(); // Endless loop
count++;
if (count > 100)
{
P1OUT ^= 0x01; // Toggle LED to show 512K bytes
count = 0; // ..have been written
data = 0x00010001;
}
}
}
void FRAMWrite(void)
{
unsigned int i=0;
for ( i= 0; i<128; i++)
{
*FRAM_write_ptr++ = data;
}
}
But When I tested example, It goes beyond the FRAM allocated section.
Is there any other method for writing on to FRAM.?
I am trying to convert char variables into Unsigned int. my code is
char spi(char data)
{
//Start transmision
SPDR = data;
//Wait for transmision complete
while(!(SPSR & 0x80));
return SPDR;
}
unsigned int ReadAd(void)
{
unsigned int data;
ChipSelectAd(1);
//Read data
CheckStatus();
spi(0x58);
data = (spi(0xFF)<< 8);
data |= spi(0xFF);
return data;
}
Actually my problem is The spi function return an 8bit char so the above code shifts left 8bits the char variable and then assigns it to a 16bit variable, the result will always be 0.
In order to actually shift the data to the left I need to typecast them first to a 16bit type variable. I have tried like this
char spi(char data)
{
//Start transmision
SPDR = data;
//Wait for transmision complete
while(!(SPSR & 0x80));
return SPDR;
}
unsigned int ReadAd(void)
{
unsigned int data;
ChipSelectAd(1);
//Read data
CheckStatus();
spi(0x58);
data = (unsigned int)((unsigned char)spi(0xFF)<< 8);
data |= (unsigned int)((unsigned char)spi(0xFF));
return data;
}
void CheckStatus(void)
{
//char adcStatus;
adcStatus = 0xFF;
//Read status
while(!(adcStatus & 0x80))
{
spi(0x40);
adcStatus = spi(0xFF);
}
}
void ChipSelectAd(char s)
{
if(s == 1){
PORTB.3 = 0; //Switch on ADC
//while(PINB.3); //Wait for chip select pin
}
else
PORTB.3 = 1; //Switch off ADC
}
its not working. please suggest me which function i have to use.
Thanks in advance.
Your problem is not the casts. It works the same without them, due to the integral promotion rules.
#include <stdio.h>
char spi ( char data )
{
char SPDR = data;
return SPDR;
}
unsigned int ReadAd ( void )
{
unsigned int data;
data = spi ( 0x81 ) << 8;
data |= spi ( 0x42 );
return data;
}
int main ( void )
{
printf ( "Result %x\n", ReadAd() );
return 0;
}
This outputs Result ffff8142 on a system where char is a signed type. To get to the real problem, try assinging the values of spi() calls to variables and then print their values. Please also show us the declaration/definition of SPDR.
1) in embedded systems: get rid of the standard integer types, the default char type in particular. If you have a modern compiler, use uint8_t, uint16_t etc from stdint.h. If you have an ancient compiler, then typedef unsigned char uint8_t and so on. If you aren't using unsigned types of known size in embedded systems, you are asking for bugs bugs bugs.
2) Learn and understand integer promotion rules. It is frightening how many programmers there are that don't know about them or understand them.
Once you have the two above fundamentals sorted out, your code should look something like this code:
(I took the liberty to fix various suspicious, possible bugs and the crappy, inconsistent indention. Plus some style nitpicks.)
#include <stdint.h>
uint8_t spi (uint8_t data)
{
SPDR = data; //Start transmision
while((SPSR & 0x80) > 0) //Wait for transmision complete
;
return SPDR;
}
uint16_t ReadAd(void)
{
uint16_t data;
ChipSelectAd(true);
CheckStatus(); //Read data
(void) spi(0x58);
data = ((uint16_t)spi(0xFF)) << 8;
data |= (uint16_t)spi(0xFF);
return data;
}
void CheckStatus(void)
{
uint8_t adcStatus;
do
{
(void) spi(0x40);
adcStatus = spi(0xFF);
} while((adcStatus & 0x80) > 0);
}
void ChipSelectAd(bool on)
{
if(on)
{
PORTB.3 = 0; //Switch on ADC
}
else
{
PORTB.3 = 1; //Switch off ADC
}
}