Cannot write to flash memory - STM32L462 - arm

I'm trying to flash data to my flash memory by parsing the hex file sent over UART. But after erasing the flash, I can't write to it. This is my code:
Code to erase flash:
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR | FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR |FLASH_FLAG_PGSERR);
/* Get the 1st page to erase */
FirstPage = ADDR_FLASH_PAGE_12;
/* Get the number of pages to erase from 1st page */
NbOfPages = 243;
/* Get the bank */
BankNumber = FLASH_BANK_1;
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.Banks = BankNumber;
EraseInitStruct.Page = FirstPage;
EraseInitStruct.NbPages = NbOfPages;
HAL_FLASHEx_Erase(&EraseInitStruct,&PAGEError);
Code to write flash:
uint64_t flashData = 0;
uint32_t flashWriteAddress = (extendedAddress | recordAddress | k);
nibbleArrayToUInt64(&data[recordDataOffset],(uint32_t)i); //convert nibble[] to uint64_t and store in flashData
CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,flashWriteAddress,(uint64_t)flashData);
Code to convert nibble array to uint64_t:
void nibbleArrayToUInt64(uint8_t* var, uint32_t lowest_pos)
{
uint8_t byte;
flashData = 0;
for(int j=0;j<16;j+=2)
{
byte = (((uint64_t)(var[lowest_pos+j]<<4 | var[lowest_pos+j+1])));
flashData |= (((uint64_t)byte) << (8*(7-(j/2))));
}
}
The error flags triggered are :
HAL_FLASH_ERROR_PROG
HAL_FLASH_ERROR_PGA
HAL_FLASH_ERROR_PGS
I don't know what mistake I'm doing. Can someone please help me?

You should unlock the flash before erase or write. For example:
HAL_FLASH_Unlock();
FLASH_EraseInitTypeDef pEraseInit;
pEraseInit.Banks = 0;
pEraseInit.NbSectors = 1;
pEraseInit.Sector = FLASH_SECTOR_2;
pEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;
pEraseInit.VoltageRange = FLASH_VOLTAGE_RANGE_3;
uint32_t sectorError;
HAL_FLASHEx_Erase(&pEraseInit, &sectorError);
HAL_FLASH_Unlock();
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, VERSION_SAVE_ADDRESS, version);
HAL_FLASH_Lock();

Related

How to make an array to send the data to slave in AVR

I'm working on an AVR to learn it. my code is working properly. mean it gave me the output same as I want but I want to modify the code. I made 4 functions to send the data to the slave. like as it's in the code I want to send 61,62,63,64. but for these, I make four functions. Now I want to modify it as all the data send to the salve by one function. so my line of code will be reduced. second I want that once the 61 sends to the salve it prints something like datatransfered and once the dataexchange it's display **exchanged**. I tried to make the array and take numbers one by one but was unlucky.
#include <xc.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
void SPI0_init(void);
void LTCSelect(void);
void LTCDeselect(void);
uint8_t SPI0_exchangeData(uint8_t data);
uint8_t SPI1_exchangeData(uint8_t data1);
uint8_t SPI2_exchangeData(uint8_t data2);
uint8_t SPI3_exchangeData(uint8_t data3);
void SPI0_init(void){
PORTA.DIR |= PIN4_bm; /* Set MOSI pin direction to output (output to LTC2983) */
PORTA.DIR &= ~PIN5_bm; /* Set MISO pin direction to input (input form LTC2983) */
PORTA.DIR |= PIN6_bm; /* Set SCK pin direction to output (output to LTC2983) */
PORTA.DIR |= PIN7_bm; /* Set CS pin direction to output (output to LTC2983) */
SPI0.CTRLA = SPI_CLK2X_bm /* Enable double-speed */
| SPI_DORD_bm /* LSB is transmitted first */
| SPI_ENABLE_bm /* Enable module */
| SPI_MASTER_bm /* SPI module in Master mode */
| SPI_PRESC_DIV16_gc; /* System Clock divided by 16 */}
uint8_t SPI0_exchangeData(uint8_t data){
SPI0.DATA = data;
while (!(SPI0.INTFLAGS & SPI_IF_bm)) /* waits until data is exchanged*/
{
}
return SPI0.DATA;}
uint8_t SPI1_exchangeData(uint8_t data1)
{
SPI0.DATA = data1;
while (!(SPI0.INTFLAGS & SPI_IF_bm)) /* waits until data is exchanged*/
{
}
return SPI0.DATA;}
uint8_t SPI2_exchangeData(uint8_t data2){
SPI0.DATA = data2;
while (!(SPI0.INTFLAGS & SPI_IF_bm)) /* waits until data is exchanged*/
{
}
return SPI0.DATA;}
uint8_t SPI3_exchangeData(uint8_t data3){
SPI0.DATA = data3;
while (!(SPI0.INTFLAGS & SPI_IF_bm)) /* waits until data is exchanged*/
{
}
return SPI0.DATA;}
void LTCSelect(void){
PORTA.OUT &= ~PIN7_bm; // Set SS pin value to LOW}
void LTCDeselect(void){
PORTA.OUT |= PIN7_bm; // Set SS pin value to HIGH}
int main(void){
uint8_t data = 61;
uint8_t data1 = 62;
uint8_t data2 = 63;
uint8_t data3 = 64;
SPI0_init();
while(1){
LTCSelect();
SPI0_exchangeData(data);
SPI1_exchangeData(data1);
SPI2_exchangeData(data2);
SPI3_exchangeData(data3);
LTCDeselect();
}}
Just use the first function. The others are just a copy, are the same and unnecessary.
uint8_t SPI0_exchangeData(uint8_t data){
SPI0.DATA = data;
while (!(SPI0.INTFLAGS & SPI_IF_bm)) /* waits until data is exchanged*/
{
}
return SPI0.DATA;
}
and in your main loop call the same function to send all your data:
int main(void){
uint8_t data = 61;
uint8_t data1 = 62;
uint8_t data2 = 63;
uint8_t data3 = 64;
SPI0_init();
while(1){
LTCSelect();
SPI0_exchangeData(data);
SPI0_exchangeData(data1);
SPI0_exchangeData(data2);
SPI0_exchangeData(data3);
LTCDeselect();
}
}
There you shuld have your numbers respectively in your slave device.
Update for sending array
/**
* Sends an uint8_t array to SPI0
*
* Here we send an array of uint8_t (aka unsigned char) to SPI0 one by one.
* using the length parameter and an index variable.
*
* #param data a data array to send to SPI0.
* #param length the length of the given array.
* #returns nothing, but you can return any util info if you wish
*/
void sendArray(uint8_t data[], uint8_t length) {
for(uint8_t i = 0; i < length; i++) {
SPI0_exchangeData(data[i]);
}
}
// Suppose we have an array named buffer
uint8_t buffer[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
// Some where in the main loop we want to send it to the SPI0
int main(void) {
//...
while(1) {
//...
// We pass the array and its length in this way
sendArray(buffer, sizeof(buffer));
}
return 0;
}
Note that the array is defined and assigned statically. In real cases the arrays mostly used with a statically allocated memory, say 64 bytes i.e. uint8_t buffer[64];, but this does not mean that it will contain data in full capacity. Hence when the data is written to an array must be counted and stored in a variable to know the actual length of that array when needed.

stm32l4 RTC HAL not working

I'm having a strange behavior with the RTC on a stm32L476 with FreeRTOS.
It only reads the first time in RUN mode, RTC is working, because from run to run it saves the value of the internal register and is going up.
Also if I do DEBUG when I put breakpoint at stm32l4xx_hal_rtc.c at line 583:
tmpreg = (uint32_t)(hrtc->Instance->TR & RTC_TR_RESERVED_MASK);
*breakpoint* sTime->Hours = (uint8_t)((tmpreg & (RTC_TR_HT | RTC_TR_HU)) >> 16);
I can see the tmpreg and TR register how they update, and then when I click jump to next breakpoint witch is the same I saw the display updated.
So why it's not working when normal RUN?
Init code (cube MX generated):
void MX_RTC_Init(void)
{
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
/**Initialize RTC Only
*/
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Initialize RTC and set the Time and Date
*/
if(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0) != 0x32F2){
sTime.Hours = 0;
sTime.Minutes = 0;
sTime.Seconds = 0;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sDate.WeekDay = RTC_WEEKDAY_MONDAY;
sDate.Month = RTC_MONTH_JANUARY;
sDate.Date = 1;
sDate.Year = 0;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,0x32F2);
}
}
void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
{
if(rtcHandle->Instance==RTC)
{
/* USER CODE BEGIN RTC_MspInit 0 */
/* USER CODE END RTC_MspInit 0 */
/* RTC clock enable */
__HAL_RCC_RTC_ENABLE();
/* USER CODE BEGIN RTC_MspInit 1 */
/* USER CODE END RTC_MspInit 1 */
}
}
task where clock is readed and printed all this task and functions are at the same menu.c:
void MenuTask(void const *argument){
for(;;){
/*
* Menus
*/
DrawMenu();
osDelay(100);
}
}
void DrawMenu(){
switch(menuTaskStatus){
/* Not important code */
case MENU_INFO:
menuInfoBar();
break;
}
}
I print on the LCD a bar with the clock in the middle
void menuInfoBar(){
//Clock
CheckClock();
if(updateNeeded.Clock){
DrawClock();
updateNeeded.Clock = 0;
}
}
Here is the problematic part, as you can see I have tried a wait for synchro but also didn't work. I have some doubts of how does this syncro and RTC reading works.
void CheckClock(){
RTC_TimeTypeDef timeVar;
// HAL_GPIO_TogglePin(LEDR_GPIO_Port, LEDR_Pin);
// if(HAL_RTC_WaitForSynchro(&hrtc) == HAL_OK){
while(HAL_RTC_GetTime(&hrtc,&timeVar,RTC_FORMAT_BIN)!= HAL_OK);
if(timeVar.Seconds != timeVarAnt.Seconds){
timeVarAnt.Minutes = timeVar.Minutes;
timeVarAnt.Hours = timeVar.Hours;
timeVarAnt.Seconds = timeVar.Seconds;
updateNeeded.Clock = 1;
}
// }
}
Here I only draw the clock on my display
void DrawClock(){
DISP_locate(49,0);
sprintf((char *)stringBuffer,"%02d:%02d:%02d",(int)timeVarAnt.Hours,(int)timeVarAnt.Minutes,(int)timeVarAnt.Seconds);
DISP_puts((char *)stringBuffer);
}
It's possible I can't read the RTC fast as 100ms?
some one could explain to me why is needed a syncronitzation? datasheet explains that if the clock is 7 time faster is ok, I'm using an 80Mhz APB1 clock
some tutorials and examples I've found the do the exact same I do, but they read on the main loop with osDelay() of many values. Is a problem using freeRTOS and reading from a task?
time has nothing to do I've tried with 5s delay and also don't works
Thanks
A little late may be but I ran into the same problem and it turns out that the HAL_GetTime(..) function has a quirk. HAL_RTC_GetDate() must be called after it to unlock the values.
You must call HAL_RTC_GetDate() after HAL_RTC_GetTime() to unlock the values
* in the higher-order calendar shadow registers to ensure consistency between the time and date values.
* Reading RTC current time locks the values in calendar shadow registers until current date is read.
This is written as a note in their documentation as well as in the source code of the RTC HAL driver.
Personally, I believe that ST's guys should've made a HAL_RTC_GetTimeAndDate() and spare us falling in this trap.
struct
{
unsigned TR;
}*rcc = (void *)0x56456546;
typedef struct
{
unsigned su :4;
unsigned st :2;
unsigned :1;
unsigned mu :4;
unsigned mt :2;
unsigned :1;
unsigned hu :4;
unsigned ht :2;
unsigned pm :1;
unsigned :9
}RCC_TR_T;
typedef struct
{
uint8_t seconds, minutes, hours, pm;
}TIME_T;
TIME_T *GetTime(TIME_T *time)
{
RCC_TR_T *tr = (RCC_TR_T *)&rcc -> TR;
time -> hours = tr -> hu + tr -> ht * 10;
time -> minutes = tr -> mu + tr -> mt * 10;
time -> seconds = tr -> su + tr -> st * 10;
time -> pm = tr -> pm;
return time;
}
This Answer don't answers why the ST "hal" don't works, but it solves what I need, that is using RTC.
This is my new CheckClock function:
void CheckClock(){
uint32_t tmpreg = (uint32_t) hrtc.Instance->TR;
/* Fill the structure fields with the read parameters */
timeVar.Hours = (uint8_t)((tmpreg & (RTC_TR_HT | RTC_TR_HU)) >> 16);
timeVar.Minutes = (uint8_t)((tmpreg & (RTC_TR_MNT | RTC_TR_MNU)) >>8);
timeVar.Seconds = (uint8_t)(tmpreg & (RTC_TR_ST | RTC_TR_SU));
if(timeVar.Seconds != timeVarAnt.Seconds){
HAL_GPIO_TogglePin(LEDR_GPIO_Port, LEDR_Pin);
timeVarAnt.Minutes = timeVar.Minutes;
timeVarAnt.Hours = timeVar.Hours;
timeVarAnt.Seconds = timeVar.Seconds;
updateNeeded.Clock = 1;
}
}
Thanks
EDIT 05/2018 :
void CheckClock(){
uint32_t tmpreg = (uint32_t) hrtc.Instance->TR;
timeVar.Hours = Bcd2ToByte((uint8_t)((tmpreg & (RTC_TR_HT | RTC_TR_HU)) >> 16));
timeVar.Minutes =Bcd2ToByte( (uint8_t)((tmpreg & (RTC_TR_MNT | RTC_TR_MNU)) >>8));
timeVar.Seconds =Bcd2ToByte( (uint8_t)(tmpreg & (RTC_TR_ST | RTC_TR_SU)));
if(timeVar.Seconds != timeVarAnt.Seconds){
timeVarAnt.Minutes = timeVar.Minutes;
timeVarAnt.Hours = timeVar.Hours;
timeVarAnt.Seconds = timeVar.Seconds;
IBS.updates.Clock = 1;
}
// }
}
//HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
char xsa[6];
char your_time[9];
sprintf(xsa,"%06x",(uint32_t)hrtc.Instance->TR);
sprintf((char*)your_time,"%c%c:%c%c:%c%c%c",xsa[0],xsa[1],xsa[2],xsa[3],xsa[4],xsa[5],'\0');

ADC on AT91SAM7 with DMA

I'm trying to write a code for ADC DMA. In my perspective, I've initiated ADC correctly. But it doesn't work and it doesn't interrupt. What am I missing? I initiated ADC and Interrupt and I am willing to access data on the interrupt.
Here is my code:
void __irq ISR_adc(void)
{
volatile AT91PS_ADC pADC = AT91C_BASE_ADC;
unsigned int AdcStatus = AT91C_BASE_ADC->ADC_SR;
unsigned short* ADC_Ptr;
unsigned short* ADC_Ptr_Next;
printf("ADC is: %d\n",Buffer1[0]);
if(((AdcStatus & AT91C_ADC_RXBUFF) == AT91C_ADC_RXBUFF) &&
((AdcStatus & AT91C_ADC_ENDRX) == AT91C_ADC_ENDRX))
{//Both bit set when get the end of next buffer
pADC->ADC_RPR = (unsigned long) Buffer1; // Receive Pointer Register
pADC->ADC_RCR = AD_DATA_BUFFER_SIZE; // Receive Counter Register
pADC->ADC_RNPR = (unsigned long)0; // Receive Next Pointer Register
pADC->ADC_RNCR = 0 ; // Receive Next Counter Registe
}
else if((AdcStatus & AT91C_ADC_ENDRX) == AT91C_ADC_ENDRX)
{//ENDRX bit set when reach the end of buffer.
pADC->ADC_RNCR = AD_DATA_BUFFER_SIZE;
}
*AT91C_AIC_EOICR = 0; // end of interrupts
}
void Configure_AD(void)
{
int i;
volatile AT91PS_ADC pADC = AT91C_BASE_ADC; // create a pointer to USART0 structure
volatile AT91PS_AIC pAIC = AT91C_BASE_AIC; // pointer to AIC data structure
volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA; // pointer to PIO data structure
volatile AT91PS_PMC pPMC = AT91C_BASE_PMC; // pointer to PMC data structure
#define AD_PRESCAL 1
#define AD_STARTUP 1
#define AD_SHTIM 2
// Enable peripheral clock
pPMC->PMC_PCER = 1 << AT91C_ID_ADC;
//Notice: After ADC_SR = 0xc000 after Reset;
pADC->ADC_CR = AT91C_ADC_SWRST; //Reset AD
//Rxternal trigger: TIOA2 output pulse; Get data using ISP.
pADC->ADC_MR = ((AD_SHTIM << 24) | (AD_STARTUP << 16) | (AD_PRESCAL <<8) | AT91C_ADC_TRGEN_EN | AT91C_ADC_TRGSEL_TIOA2);
pADC->ADC_CHER = AT91C_ADC_CH4; //channel 4 enable
//Configure PDC; Write Counter Register reset ADC_SR.
pADC->ADC_PTCR = AT91C_PDC_RXTDIS ;
pADC->ADC_RPR = (unsigned long)Buffer1; // Receive Pointer Register
pADC->ADC_RCR = AD_DATA_BUFFER_SIZE; // Receive Counter Register
pADC->ADC_RNPR = (unsigned long)0; // Receive Next Pointer Register
pADC-> ADC_RNCR = 0 ; // Receive Next Counter Register
pADC->ADC_PTCR = AT91C_PDC_RXTEN ; //Enable PDC
pADC->ADC_IER = AT91C_ADC_ENDRX | AT91C_ADC_RXBUFF; //enable interrupt on transfer complete
pAIC->AIC_IDCR = (1<<AT91C_ID_ADC);
pAIC->AIC_SVR[AT91C_ID_ADC] = (unsigned int)ISR_adc;
pAIC->AIC_SMR[AT91C_ID_ADC] = (AT91C_AIC_PRIOR_LOWEST | 0x4 );
pAIC->AIC_IECR = (1<<AT91C_ID_ADC);
}

errors encountered while interfacing eeprom with microcontroller

I am not an expert c programmers and in the c code I m getting these kinds of errors. I got many and tried to sort them out but can not solve these. The code is as follows:
/*
* EEPROM.c
* interfacing microchip 24aa64f IC with atmel sam4e
*/
#include <asf.h>
#include "EEPROM_I2C.h"
#define DEVICE_ADDRESS 0x50 // 7-bit device identifier 0101000, (refer datasheet)
//#define EEPROM_NAME 24AA6F
#define I2C_FAST_MODE_SPEED 400000//TWI_BUS_CLOCK 400KHz
#define TWI_CLK_DIVIDER 2
#define TWI_CLK_DIV_MIN 7
#define TWI_CLK_CALC_ARGU 4
#define TWI_CLK_DIV_MAX 0xFF
/*************************** Main function ******************************/
int eeprom_main( void )
{
struct micro24 ptMicro24 ;
typedef struct twi_options twi_options_t;
typedef struct Twi_registers Twi;
char TxBuffer[128] ;
char RxBuffer[128] ;
int BufferIndex;
unsigned int PageCount;
unsigned int error = 0 ;
unsigned int i;
ptMicro24.PageSize = 32;
ptMicro24.NumOfPage = 128;
ptMicro24.EepromSize = 128*32;
ptMicro24.SlaveAddress = DEVICE_ADDRESS;
ptMicro24.EepromName = 64;
/***************************** CLOCK SETTINGS TO GET 400KHz **********************
* Set the I2C bus speed in conjunction with the clock frequency.
* param p_twi Pointer to a TWI instance.
* return value PASS\Fail New speed setting is accepted\rejected
**********************************************************************************/
uint32_t twi_set_speed(struct Twi_registers *Twi, uint32_t ul_speed, uint32_t ul_mck)
//uint32_t twi_set_speed(Twi *p_twi, uint32_t ul_speed, uint32_t ul_mck)
{
uint32_t ckdiv = 0; //clock divider is used to increase both TWCK high and low periods (16-18)
uint32_t c_lh_div; //CHDIV (0-7) and CLDIV (8-15)
if (ul_speed > I2C_FAST_MODE_SPEED) { //ul_speed is the desired I2C bus speed
return FAIL;
}
c_lh_div = ul_mck / (ul_speed * TWI_CLK_DIVIDER) - TWI_CLK_CALC_ARGU; //ul_mck main clock of the device
/* cldiv must fit in 8 bits, ckdiv must fit in 3 bits */
while ((c_lh_div > TWI_CLK_DIV_MAX) && (ckdiv < TWI_CLK_DIV_MIN))
{
ckdiv++; // Increase clock divider
c_lh_div /= TWI_CLK_DIVIDER; //Divide cldiv value
}
/* set clock waveform generator register */
Twi->TWI_CWGR =
TWI_CWGR_CLDIV(c_lh_div) | TWI_CWGR_CHDIV(c_lh_div) |
TWI_CWGR_CKDIV(ckdiv);
return PASS;
}
/************************************ Initialize TWI master mode ************************
* Set the control register TWI_CR by MSEN and SVDIS
* param p_opt Options for initializing the TWI module
* return TWI_SUCCESS if initialization is complete
* twi_options... structure contains clock speed, master clock, chip and smbus
*****************************************************************************************/
uint32_t twi_master_start(struct Twi_registers *Twi, struct twi_options_t *twi_options_t)
//uint32_t twi_master_start(Twi *p_twi, const twi_options_t *p_opt)
{
uint32_t status = TWI_SUCCESS; // status success return code is 0
// Enable master mode and disable slave mode in TWI_CR
Twi -> TWI_CR_START = TWI_CR_START;
Twi->TWI_CR_MSEN = TWI_CR_MSEN; // Set Master Enable bit
Twi->TWI_CR_SVDIS = TWI_CR_SVDIS; // Set Slave Disable bit
/* Select the speed */
//new//if (twi_set_speed(Twi->TWI_SR, twi_options_t->speed, twi_options_t->master_clk) == FAIL)
//if (twi_set_speed(Twi, twi_options_t->speed, twi_options_t->master_clk) == FAIL)
//{
//status = TWI_INVALID_ARGUMENT; /* The desired speed setting is rejected */
//}
if (twi_options_t->smbus == 0)
{
Twi->TWI_CR_QUICK == 0;
status = TWI_INVALID_ARGUMENT;
}
else
if (twi_options_t->smbus == 1)
{
Twi->TWI_CR_QUICK == 1;
status = TWI_SUCCESS;
}
return status;
}
/***************************** WriteByte Function ********************************
This function uses a two bytes internal address (IADR) along with
Internal word address of eeprom.
Return Value: None
***********************************************************************************/
void WriteByte (struct micro24 *ptMicro24, char Data2Write,
unsigned int Address)
//Data2Write is the data to be written n the eeprom
//struct <micro24 *ptMicro24> : Structure of Microchip 24AA Two-wire Eeprom
//unsigned int Address>: Address where to write
{
unsigned int WordAddress;
unsigned int SlaveAddress;
unsigned char p0=0;
TWI_CR_START ==1;
if (ptMicro24->EepromName == 64 )
{
if ( Address > 0xFFFF)
{
p0 = 1;
/* Mask the 17th bit to get the 16th LSB */
WordAddress = Address & 0xFFFF ;
SlaveAddress = ptMicro24->SlaveAddress + (p0<<16) ;
}
else {
SlaveAddress = ptMicro24->SlaveAddress ;
WordAddress = Address ;
}
}
TWI_CR_STOP ==1;
//TWI_WriteSingleIadr(TWI_IADR_IADR,SlaveAddress, WordAddress,
// TWI_MMR_IADRSZ_2_BYTE, &Data2Write); // declared as extern
// to write to internal address, utilizing internal address and master mode register
//}
/******************** Increase Speed Function *****************************
* TWI is accessed without calling TWI functions
/***************************************************************************/
int NumOfBytes, Count;
int status;
uint32_t Buffer;
/* Enable Master Mode of the TWI */
TWI_CR_MSEN == 1;
// Twi.TWI_CR_MSEN ==1;
//TWI_CR->TWI_CR_MSEN = TWI_CR_MSEN ;
/* Set the TWI Master Mode Register */
Twi->TWI_MMR = (SlaveAddress & (~TWI_MMR_MREAD) | (TWI_MMR_IADRSZ_2_BYTE));
/* Set the internal address to access the wanted page */
Twi -> TWI_IADR = WordAddress ;
/* Wait until TXRDY is high to transmit the next data */
status = TWI_SR_TXRDY;
while (!(status & TWI_SR_TXRDY))
status = TWI_SR_TXRDY;
/* Send the buffer to the page */
for (Count=0; Count < NumOfBytes ;Count++ )
{
Twi ->TWI_THR_TXDATA = Buffer++;
/* Wait until TXRDY is high to transmit the next data */
status = TWI_SR_TXRDY;
while (!(status & TWI_SR_TXRDY))
status = TWI_SR_TXRDY;
}
/* Wait for the Transmit complete is set */
status = TWI_SR_TXCOMP;
while (!(status & TWI_SR_TXCOMP))
status = TWI_SR_TXCOMP;
// add some wait function according to datasheet before sending the next data
// e.g: 10ms
// e.g: WaitMiliSecond (10);
}
/****************************** ReadByte Function **************************
This function uses a two bytes internal address (IADR) along with
Internal word address of eeprom.
Return Value: None
****************************************************************************/
char ReadByte (struct micro24 *ptMicro24,
unsigned int Address) //int Address to read
{
unsigned int WordAddress;
unsigned int SlaveAddress;
char Data2Read ;
unsigned char p0=0;
TWI_CR_START == 1;
//p_twi -> TWI_CR_START = TWI_CR_START;
if (ptMicro24->EepromName == 64)
{
if ( Address > 0xFFFF) {
p0 = 1;
// Mask the 17th bit to get the 16th LSB
WordAddress = Address & 0xFFFF ;
SlaveAddress = ptMicro24->SlaveAddress + (p0<<16) ;
}
else {
SlaveAddress = ptMicro24->SlaveAddress ;
WordAddress = Address ;
}
}
//TWI_ReadSingleIadr(TWI_IADR_IADR,SlaveAddress,WordAddress,
// TWI_MMR_IADRSZ_2_BYTE,&Data2Read);
// declared as extern
// to write to internal address, utilizing internal address and master mode register
return (Data2Read);
}
}
errors are:
(24,19): error: storage size of 'ptMicro24' isn't known
67,5): error: dereferencing pointer to incomplete type
Twi->TWI_CWGR =
error: expected identifier before '(' token
#define TWI_CR_START (0x1u << 0) /**< \brief (TWI_CR) Send a START Condition */
error: expected identifier before '(' token
#define TWI_CR_MSEN (0x1u << 2) /**< \brief (TWI_CR) TWI Master Mode Enabled */
error: expected identifier before '(' token
#define TWI_CR_SVDIS (0x1u << 5) /**< \brief (TWI_CR) TWI Slave Mode Disabled */
error: dereferencing pointer to incomplete type
if (twi_options_t->smbus == 0)
It seems missing the declaration of struct micro24, this may be the cause of first error: error: storage size of 'ptMicro24' isn't known.
The same for declaration of Twi_registers, that is causing other errors.
Either you forgot to declare these structs or to include an header file declaring them.

Saving data to External EEPROM with PIC18

I have PIC18F87J11 with 25LC1024 external EEPROM, and I would like to store some data on it and be able to read it later on. I have done some research, but unfortunately I could not find a tutorial that uses similar board as mine. I am using MPLAB IDE with C18 compiler.
PIC18F87J11
Note: two more links are written as comment below.
This is where my problem is ...
In order to write to the 25LC1024 external EEPROM I followed the tutorial from microchip. The first problem is that this tut is written for PIC18F1220 and I'm using PIC18F87J11. So upon opening the project I get two files not found error, but I simply ignored them.
PICTURE
I copied the file AN1018.h and AN1018_SPI.c to the project I am working on, and I copied some piece of code from AN1018.c file.
Code from AN1018.c file
void main(void)
{
#define PAGESIZE 16
static unsigned char data[PAGESIZE]; // One-page data array
static unsigned char i;
init(); // Initialize PIC
data[0] = 0xCC; // Initialize first data byte
/* Low-density byte function calls */
LowDensByteWrite(data[0], 0x133); // Write 1 byte of data at 0x133
data[0] = 0xFF;
LowDensByteRead(data, 0x133);
printf("%x",data);
while(1){};
}
void init(void)
{
ADCON1 = 0x7F; // Configure digital I/O
PORTA = 0x08; // Set CS high (inactive)
TRISA = 0b11110111; // Configure PORTA I/O
PORTB = 0; // Clear all PORTB pins
TRISB = 0b11111100; // Configure PORTB I/O
}
My second problem is that the output message is always 1e0. In other words, I do not know if the write was successfully made or not. Also I am not sure about what I might be missing.
If I can receive some kind of help, I would appreciate it. To sum up everything, I want to store data to my external EEPROM and retain it when needed. Please know I am a beginner with Microcontroller programming.
As a first step (before reading & writing) you have to be sure that your SPI interface (hardware and software) is correctly configured. To check this step you can read the "Status Register" from the 25LC1024. Look the datasheet for "RDSR", the instruction to send to the eeprom should be 0b00000101 so (int)5.
Here some code for 18F* + 25LC* wirtten in sdcc of a really old project. The code is very basic, no external library used, you just have to replace register variable names and init config for your pic.
Some code comes from here, thanks to bitberzerkir!
spi.c
#ifndef SPI_HH
#define SPI_HH
#define SpiWrite(x) spiRW(x)
#define SpiRead() spiRW(0)
unsigned char spiRW(unsigned char data_){
SSPBUF = data_;
while(!PIR1bits.SSPIF);
PIR1bits.SSPIF = 0;
return SSPBUF;
}
void SpiInit() {
SSPSTAT = 0x40; // 01000000
SSPCON1 = 0x20; // 00100000
PIR1bits.SSPIF = 0;
}
#endif
eeprom.c
Note: Since the addr of 25LC1024 are 3x8bits make sure your compiler 'long' type has at least 24bit
#ifndef EEPROM_HH
#define EEPROM_HH
#include "spi.c"
#define CS PORTCbits.RC2
void EepromInit() {
SpiInit();
CS = 1;
}
unsigned char EReadStatus () {
unsigned char c;
CS = 0;
SpiWrite(0x05);
c = SpiRead();
CS = 1;
return c;
}
unsigned char EWriting() {
unsigned char c;
CS = 0;
SpiWrite(0x05);
c = SpiRead();
CS = 1;
return c & 1;
}
unsigned char EReadCh (unsigned long addr) {
unsigned char c;
// Send READ command and addr, then read data
CS = 0;
SpiWrite(0x03);
// Address in 3x8 bit mode for 25lc1024
SpiWrite(addr>>16);
SpiWrite(addr>>8);
SpiWrite((unsigned char) addr);
c = SpiRead();
CS = 1;
return c;
}
void EWriteCh (unsigned char c, unsigned long addr) {
// Enable Write Latch
CS = 0;
SpiWrite(0x06);
CS = 1;
// Send WRITE command, addr and data
CS = 0;
SpiWrite(0x02);
SpiWrite(addr>>16);
SpiWrite(addr>>8);
SpiWrite((unsigned char) addr);
SpiWrite(c);
CS = 1;
}
#endif
main.c
Set your init according to the datasheet
#include <pic18fregs.h>
#include "eeprom.c"
void main(void) {
char out;
TRISB = 0x01;
TRISC = 0x00;
PORTB = 0x00;
PORTC = 0x00;
EepromInit();
EWriteCh('a', 0x00);
out = EReadCh(0x00);
while(1);
}
If you want to read/write a buffer take care of pagination. Eg here:
// Page byte size, 64 for 25lc256 and 256 for 25lc1024
#define PSIZE 256
// Addr mem limit 7FFF for 25lc256, 1FFFF for 25lc1024
#define MLIMIT 0x1FFFF
void EReadBuff (unsigned char c[], unsigned long dim, unsigned long addr) {
unsigned int i;
// Send READ command and addr, then read data
CS = 0;
SpiWrite(0x03);
SpiWrite(addr>>16);
SpiWrite(addr>>8);
SpiWrite((unsigned char) addr);
for(i = 0; i < dim; ++i)
c[i] = SpiRead();
CS = 1;
}
void EWriteBuff (unsigned char c[], unsigned long dim, unsigned long addr) {
unsigned char i;
unsigned int begin = 0;
unsigned int end = dim > PSIZE ? PSIZE : dim;
while (end > begin && addr + end <= MLIMIT) { // check if addr is a siutable address [0, MLIMIT]
// Enable Write Latch
CS = 0;
SpiWrite(0x06);
CS = 1;
// Send WRITE command, addr and data
CS = 0;
SpiWrite(0x02);
SpiWrite(addr>>8);
SpiWrite((unsigned char) addr);
for(i = begin; i < end; ++i)
SpiWrite(c[i]);
CS = 1;
while(EWriting());
dim -= PSIZE;
begin += PSIZE;
addr += PSIZE;
end = begin + (dim > PSIZE ? PSIZE : dim);
}
}
#endif
I think before directly using the AN1018.h/AN1018_spi.c you will need to verify that it is compatible with your micro-controller. I recommend to check the datasheet of both micro-controllers and see the difference specifically for SPI module as the external EEPROM which you are using will be connected to SPI bus. If these two micro-controller has same register configuration/module for SPI then you can use it else you will have to write the driver on your own. You can use AN1018_spi.c for reference I guess you will just need to change some registers if required.
Then in you init function, you are not initializing SPI module, you will need to specify correct SPI clock, SPI mode based on your external device. Once you have properly initialize SPI module. You will need to write EEPROM_Read/EEPROM_Write function. In which you will have to following protocol given in datasheet of your external device for sending/receiving data from device using.
hi i googled and get a very good website Where i found post on Interfacing external EEPROM with PIC Microcontroller via i2c protocol with FM24C64 and the code which they given in post which i tested and working fine. i give that link may it help you. http://www.nbcafe.in/interfacing-external-eeprom-with-pic-microcontroller/

Resources