Erasing my Flash on STM32L1 - c

I'm facing a problem with my erasing function.
I try to erase 15 sectors of my Flash in order to put a new binary file.
I don't understand why but my function freeze and i cannot erase all memory i need.
Here is my code if you want to give a try
/*
* bootloader.c
*
* Created on: 9 juin 2015
* Author: tgloaguen
*/
#include "usart.h"
#include "stm32l1xx_flash.h"
#define WRITE_START_ADDR 0x08000000
#define WRITE_END_ADDR 0x0800FFFF
#define FLASH_PAGE_SIZE ((uint16_t)0x100) //If a page is 256 bits
#define MY_BL_FUNCTIONS __attribute__((section(".bootsection")))
void BootLoader(void) MY_BL_FUNCTIONS;
FLASH_Status Flash_Write ( uint32_t StartAddress, uint8_t *p, uint32_t Size ) MY_BL_FUNCTIONS;
uint8_t Flash_Erase() MY_BL_FUNCTIONS;
void Receive_Data(char * buffer,int size)MY_BL_FUNCTIONS;
void Receive_Size(char * buffer, int *sizeData)MY_BL_FUNCTIONS;
void BootLoader(void) {
//clear all ITs
USART_ITConfig( USART1, USART_IT_RXNE, DISABLE );
//SendString("HELLO",USART2);
uint8_t status,i;
char buffer[33];
//en dur
uint16_t *adr = WRITE_START_ADDR;
uint16_t sizeBin = 51400,k = 0,k_hexa = 0x20;
SendString("BOOTLOADER",USART2);
Flash_Erase();
SendString("ERASEOK",USART2);
//if sizeBin ok
}
and the erase function
uint8_t Flash_Erase() {
uint32_t EraseCounter = 0x00, Address = 0x00;//Erase count, write address
uint32_t NbrOfPage = 0x00;//Recording to erase the pages
volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;/*FLASH complete erasure marks*/
/*Unlock FLASH*/
FLASH_Unlock();
/*Calculate the number of FLASH pages need to erase */
NbrOfPage = (WRITE_END_ADDR - WRITE_START_ADDR) / FLASH_PAGE_SIZE;
/* Remove all hang flags */
FLASH_ClearFlag ( FLASH_FLAG_EOP |
FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR |
FLASH_FLAG_SIZERR |
FLASH_FLAG_OPTVERR );
/* Erase the FLASH page*/
for(EraseCounter = 0; (EraseCounter <NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)
{
SendString("ok |",USART2);
FLASHStatus = FLASH_ErasePage(WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));
}
FLASH_Lock ( );
return (uint8_t)FLASHStatus;
}

In your code you are tring to erase the whole flash, but you are executing your bootloader from flash from final sectors.
As reported by th REF man
During a write/erase operation to the NVM (except Half Page programming or Double-word
erase/write), any attempt to read the same bank of NVM stalls the bus.
Then you have to preserve the space of bootloader changing WRITE_END_ADDR define according to your memory map.
Example: if your bootloader is 4K long and belongs to the last sector (0x0801 F000 - 0x0801 FFFF) then WRITE_END_ADDR must be 0x0801 EFFF.
EDIT
As #Olaf wrote take care about your ISP (Initial Stack Pointer) and IPC (Initial Program Counter) that belong to first 8 bytes in your flash at address 0.

Related

STM32L072 USB Flash Drive

I am working on an embedded C project in Keil µVision. Part of the project is to make the uC detect and operate as a USB flash drive. I am using a STM32L072 that is connected to external SPI Flash via SPI2 (P/N: SST26VF016B). I can read/write/erase/ the SST26V flash chip with no issues and I can communicate over USB with no problems. If I plug the device into a Windows based computer via USB it detects as a flash drive with the appropriate capacity (in this case 64KB[see NOTE 1 below]). Windows then will prompt me to format the drive. When I try to format the drive with the following parameters:
(Capacity: 64KB, File System: FAT (Default), Allocation unit size: 512 bytes, Quick Format: checked)
Windows will issue a bunch of reads and writes and eventually fail with an error messages that reads "Windows was unable to complete the format".
I seem to be having a problem bridging the gap between USB and SPI. I modified the usbd_storage_if.c following tutorials like this one. I only modified a few lines of code shown below:
#define STORAGE_LUN_NBR 1 // Logical Unit Number
//#define STORAGE_BLK_NBR 3840 // Use all memory in the SST26V
#define STORAGE_BLK_NBR 80 // Use ONLY the first 64kB of flash for testing.
#define STORAGE_BLK_SIZ 0x200
#define SST26V_MEMORY_OFFSET 0x10000 // This is the starting address of the SST26V's memory
....
/**
* #brief .
* #param lun: .
* #retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 6 */
printf("\r\nR%d:0x%08X", blk_len*STORAGE_BLK_SIZ, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET)); // print the size and address
_SPI_FLASH_GetData((blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET), blk_len*STORAGE_BLK_SIZ, buf);
return (USBD_OK);
/* USER CODE END 6 */
}
/**
* #brief .
* #param lun: .
* #retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 7 */
// incoming USB data packets are 512Bytes
printf("\r\nW%d:0x%08X", blk_len*STORAGE_BLK_SIZ, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET)); // print the size and address
_SPI_FLASH_WritePage(256, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET), buf); // As per SST26V datasheet, can only write 256B at a time
_SPI_FLASH_WritePage(256, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET + 256), buf+256);
return (USBD_OK);
/* USER CODE END 7 */
}
If I attempt to format the drive and then dump the 64KB flash contents over UART I get the following:
:00010000|2000000000000000200020000000000000000000000000000000000000000000
:00010020|0000000000002000000020000000000000002000200000000000200020002000
:00010040|0800100010001000000000001000000010000000000000000000000010000000
:00010060|0400040004000000040004000400800000000400000010000000000000001000
:00010080|0000010000000000010000008100000000000000010000000000010001000100
:000100A0|0100010001000000000001000000000000000100000010000000000000001000
:000100C0|0000020000008200000082008200000002000000020000000000000000000000
:000100E0|0200000000000200000002000000000000000200000000001000100010000000
:00010100|0000000000000000000000000000000000000000000000000000000000000000
... (all zeros in between these regions)
:00010C00|F8FFFF0000000000000000000000000000000000000000000000000000000000
... (all zeros in between these regions)
:00010E00|F8FFFF0000000000000000000000000000000000000000000000000000000000
... (all zeros in between these regions)
:00015000|FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
... (all FF's in between these regions)
:0001FE00|0000000000000000000000000000000000000000000000000000000000000000
:0001FE20|0000000000000000000000000000000000000000000000000000000000000000
:0001FE40|0000000000000000000000000000000000000000000000000000000000000000
:0001FE60|0000000000000000000000000000000000000000000000000000000000000000
:0001FE80|0000000000000000000000000000000000000000000000000000000000000000
:0001FEA0|0000000000000000000000000000000000000000000000000000000000000000
:0001FEC0|0000000000000000000000000000000000000000000000000000000000000000
:0001FEE0|0000000000000000000000000000000000000000000000000000000000000000
:0001FF00|0000000000000000000000000000000000000000000000000000000000000000
:0001FF20|0000000000000000000000000000000000000000000000000000000000000000
:0001FF40|0000000000000000000000000000000000000000000000000000000000000000
:0001FF60|0000000000000000000000000000000000000000000000000000000000000000
:0001FF80|0000000000000000000000000000000000000000000000000000000000000000
:0001FFA0|0000000000000000000000000000000000000000000000000000000000000000
:0001FFC0|0000000000000000000000000000000000000000000000000000000000000000
:0001FFE0|0000000000000000000000000000000000000000000000000000000000000000
Any ideas what I might be missing? I also find it slightly odd that the first 20,448 (0x4FE0) bytes is primarily zeros. This memory chip is NAND flash and so I would except all unused space to be FF's. Which makes me think; any space being written to must be erased before being written to (unless the space is already all FF's), but the smallest size I can erase on the SST26V is a sector (4 Kbyte). Does this mean the my Allocation unit size should be 4096 bytes, not 512 bytes?
NOTES
1. I'm using the first 64KB of flash to make debugging easier. Takes too long to print out entire 2MB (8Mbit) of flash over UART.
UPDATE # 1
I think I may have found the problem, but have yet to solve it. When I review all of the read write addresses that are printed out over UART I find multiple instances of Windows writing 512 bytes to address 0x00010000. Seeing as this is NAND flash it must be erased before it can be written to again, but because the smallest amount of memory that can be erased is 4kB I suppose this means that I will have to copy the 4kB flash sector to the STM32's RAM, modify the first 512 bytes, erase the 4kB flash sector, then write what I have in RAM back to the 4kB flash sector. Does that sound correct? Seems inefficient.
UPDATE # 2
I confirmed that my suspicions in UPDATE 1 were correct. I tried using only the first 512 bytes of each sector and it works, but as a result only has 1/8 of the capacity. More updates to follow.
I was able to solve my problem. I was on the correct path in UPDATES 1 & 2.
I was able to use the entire 2MB region of the external flash by creating some new functions that deal with flash memory from a sector perspective and a buffer in RAM that is the size of a sector (4KB). See code below:
/**
* #brief .
* #param lun: .
* #retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 6 */
if((blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET) == 0x00010000)
printf("\r\nR %d:0x%08X", blk_len*STORAGE_BLK_SIZ, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET)); // print the size and address
_SPI_FLASH_GetData((blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET), blk_len*STORAGE_BLK_SIZ, buf);
return (USBD_OK);
/* USER CODE END 6 */
}
/**
* #brief .
* #param lun: .
* #retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
uint8_t IsBlockEmptyFlag = 0;
uint8_t temp = 0xFF;
uint16_t sector_number = 0;
uint8_t block_number = 0;
/* USER CODE BEGIN 7 */
printf("\r\nW%d:0x%08X", blk_len*STORAGE_BLK_SIZ, (blk_addr * STORAGE_BLK_SIZ + bytes
// First, check if block that we want to write to is empty (All bytes are 0xFF)
_SPI_FLASH_GetData((blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET), blk_len*STORAGE_BLK_SIZ, RAMbuffer);
for(uint16_t i = 0; i<512; i++)
temp &= RAMbuffer[i];
if(temp == 0xFF) // then all bytes must be 0xFF and the block is ready to be writen to.
IsBlockEmptyFlag = 1;
if(IsBlockEmptyFlag) // if the block is empty already, have at it, write away
{
_SPI_FLASH_WritePage(blk_len*STORAGE_BLK_SIZ, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET), buf);
}
else // if it's not empty
{
printf("\r\nt=%02X", temp);
// Find the sector number that this block is in
sector_number = blk_addr/8;
// Save the entire flash sector to RAM
_SPI_FLASH_ReadSector(sector_number, RAMbuffer);
// Erase the sector flash sector
SST26V_FLASH_EraseSectorN(sector_number);
// compute the block number of the corresponding sector
block_number = blk_addr % 8;
// create a pointer to the RAM buffer
uint8_t *p_RAM_buffer;
p_RAM_buffer = RAMbuffer;
// Modify the RAM buffer's appropriate block
memcpy(p_RAM_buffer + (512*block_number), buf, blk_len*STORAGE_BLK_SIZ);
// Write the buffer back into external flash
_SPI_FLASH_WriteSector(sector_number, RAMbuffer);
}
return (USBD_OK);
/* USER CODE END 7 */
}

HAL drivers erase/read/write flash on STM32F4 nucleo

uint32_t PAGEError = 0;
FLASH_EraseInitTypeDef EraseInitStruct;
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS ;
EraseInitStruct.Sector = FLASH_SECTOR_0;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, 0x08000000, counter)
HAL_FLASH_Lock();
counter2 = *(__IO uint32_t *)0x08000000;
counter3 = *(__IO uint32_t *)0x08000001;
counter4 = *(__IO uint32_t *)0x08000002;
sprintf(buf, "%d", counter2); //gets send to the OLED with I2C
sprintf(buf2, "%d", counter3);
sprintf(buf3, "%d", counter4);
I want to write the variable counter to the flash and then read it as counter2.
The first flash sector starts at 0x08000000.
counter2, 3 and 4 are display trough an OLED screen.
Displaying counter2 works and shows me the value of counter-1, but it works only once. If I write again to the flash nothing seems to happen.
counter3 and counter4 don't work at all.
Output on the OLED when counter=0x00000008 after I have erased the flash but not written anything:
counter2: 536873624
counter3: -652214262
counter4: 31006720
And after writting and ressetting:
counter2: 8
counter3: -654311424
counter4: 30998528
What is going on here? Can someone tell me why all variables change?
Do I have to configure the linker?
I will treat you now as begineer, but will say sorry if you are not.
STM32 devices have flash on 0x08000000 and by erasing this sector, you did failure on startup because you erased actual part from where CPU loads instructions.
When you tried to erase sectors, you did not specify how many sectors to erase.
Reading of counters is wrong. Since you have uint32_t variable, you have to do 4-bytes between readings, something like:
counter2 = *(__IO uint32_t *)0x08000000;
counter3 = *(__IO uint32_t *)0x08000004;
counter4 = *(__IO uint32_t *)0x08000008;
Correct erasing is shown below.
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
EraseInitStruct.Sector = FLASH_SECTOR_0; //Specify sector number
EraseInitStruct.NbSectors = 1; //This is also important!
if(HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
//Erase error!
}
So, find out how long is your program and do your operations in sector after your program.
You can find example for EraseProgram in STM32CubeF4 package.
STM32Cube_FW_F4_V1.16.0\Projects\STM324x9I_EVAL\Examples\FLASH\FLASH_EraseProgram\Src\main.c
Concept will work also on your nucleo, just make sure you set correct address for flash erasing.
Thanks to #phoenix!
In Stm32CubF3 reference erasing flash works as follows:
There is to mention how a memory page address is looking:
/* Base address of the Flash sectors */
#define ADDR_FLASH_PAGE_0 ((uint32_t)0x08000000) /* Base # of Page 0, 2 Kbytes */
#define ADDR_FLASH_PAGE_1 ((uint32_t)0x08000800) /* Base # of Page 1, 2 Kbytes */
#define ADDR_FLASH_PAGE_2 ((uint32_t)0x08001000) /* Base # of Page 2, 2 Kbytes */
#define ADDR_FLASH_PAGE_3 ((uint32_t)0x08001800) /* Base # of Page 3, 2 Kbytes */
#define ADDR_FLASH_PAGE_4 ((uint32_t)0x08002000) /* Base # of Page 4, 2 Kbytes */
#define ADDR_FLASH_PAGE_5 ((uint32_t)0x08002800) /* Base # of Page 5, 2 Kbytes */
#define ADDR_FLASH_PAGE_6 ((uint32_t)0x08003000) /* Base # of Page 6, 2 Kbytes */
So your minimal code looks as follows:
I want to delete my application # 0x08003000 --> FLASH_PAGE_6. The erasing is done 2kB wise:
/* EEPROM start address in Flash */
#define EEPROM_START_ADDRESS ((uint32_t)ADDR_FLASH_PAGE_32) /* EEPROM emulation start address */
/* Pages 0 and 1 base and end addresses */
#define PAGE0_BASE_ADDRESS ((uint32_t)(EEPROM_START_ADDRESS + 0x0000))
#define PAGE0_END_ADDRESS ((uint32_t)(EEPROM_START_ADDRESS + (PAGE_SIZE - 1)))
//#define PAGE0_ID ADDR_FLASH_PAGE_32
/* Clear flash flags */
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP |
FLASH_FLAG_WRPERR |
FLASH_FLAG_PGERR);
uint32_t *flash_ptr = 0x8003000;
uint32_t page_error = 0;
HAL_StatusTypeDef flashstatus;
FLASH_EraseInitTypeDef s_eraseinit;
/* Fill EraseInit structure*/
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages = 1; // seems to be 1 !!!!
/* I want to delete 54kB in my flash --> 52kB / 2kB (per erase) = 26 iterations
After erasing one page, increment page by 0x800 = 2048 byte = 2kB = pagesize */
for(int pageCount = 0; pageCount < 26; pageCount++){
s_eraseinit.PageAddress = ADDR_FLASH_PAGE_6 + pageCount * 0x800;
flashstatus = HAL_FLASHEx_Erase(&s_eraseinit, &page_error);
}
The best way is to create the new segment of flash in the linkescriptr and place the data there. It is the safest.
If do not know linker scripts create a table of the one segment size, and place it at the end of the flash using your compiler directives.
If you do not know both I suggest a ready made STM eeprom emulation example from the Cube

Codevision AVR access external eeprom 24c02B using TWI

I'm a beginner in C. I'm trying to write and read to external eeprom (AT24c02B) then show the data bytes that store in eeprom to LED in PORTB and or to LCD. So I know the data successfully stored in eeprom.
LED in PORTB is active low.
Here is the code, i got it from cvAVR help:
#include <mega16a.h>
// Alphanumeric LCD functions
#include <alcd.h>
// Declare your global variables here
// TWI functions
#include <twi.h>
#include <delay.h>
/* 7 bit TWI bus slave address of the AT24C02B 2kbyte EEPROM */
#define EEPROM_TWI_BUS_ADDRESS (0xA0 >> 1)
void main(void)
{
// Declare your local variables here
struct
{
struct
{
unsigned char msb;
unsigned char lsb;
} addr;
unsigned char data;
} twi_eeprom;
unsigned char eeprom_rd_data;
// Input/Output Ports initialization
// Port A initialization
// Function: Bit7=Out Bit6=Out Bit5=Out Bit4=Out Bit3=Out Bit2=Out Bit1=Out Bit0=Out
DDRA=(1<<DDA7) | (1<<DDA6) | (1<<DDA5) | (1<<DDA4) | (1<<DDA3) | (1<<DDA2) | (1<<DDA1) | (1<<DDA0);
// State: Bit7=0 Bit6=0 Bit5=0 Bit4=0 Bit3=0 Bit2=0 Bit1=0 Bit0=0
PORTA=(0<<PORTA7) | (0<<PORTA6) | (0<<PORTA5) | (0<<PORTA4) | (0<<PORTA3) | (0<<PORTA2) | (0<<PORTA1) | (0<<PORTA0);
// Port B initialization
// Function: Bit7=Out Bit6=Out Bit5=Out Bit4=Out Bit3=Out Bit2=Out Bit1=Out Bit0=Out
DDRB=(1<<DDB7) | (1<<DDB6) | (1<<DDB5) | (1<<DDB4) | (1<<DDB3) | (1<<DDB2) | (1<<DDB1) | (1<<DDB0);
// State: Bit7=1 Bit6=1 Bit5=1 Bit4=1 Bit3=1 Bit2=1 Bit1=1 Bit0=1
PORTB=(1<<PORTB7) | (1<<PORTB6) | (1<<PORTB5) | (1<<PORTB4) | (1<<PORTB3) | (1<<PORTB2) | (1<<PORTB1) | (1<<PORTB0);
// TWI initialization
// Mode: TWI Master
// Bit Rate: 100 kHz
twi_master_init(100);
// Alphanumeric LCD initialization
// Connections are specified in the
// Project|Configure|C Compiler|Libraries|Alphanumeric LCD menu:
// RS - PORTA Bit 0
// RD - PORTA Bit 1
// EN - PORTA Bit 2
// D4 - PORTA Bit 4
// D5 - PORTA Bit 5
// D6 - PORTA Bit 6
// D7 - PORTA Bit 7
// Characters/line: 16
lcd_init(16);
// Global enable interrupts
#asm("sei")
/* write the byte 0x55 to the AT24C02B EEPROM address 0x210 */
twi_eeprom.addr.msb=0x02;
twi_eeprom.addr.lsb=0x10;
twi_eeprom.data=0x55;
twi_master_trans(EEPROM_TWI_BUS_ADDRESS,(unsigned char *) &twi_eeprom,3,0,0);
/* 10ms delay to complete the write operation */
delay_ms(10);
/* read the byte back into the eeprom_rd_data variable */
twi_master_trans(EEPROM_TWI_BUS_ADDRESS,(unsigned char *) &twi_eeprom,2,&eeprom_rd_data,1);
while (1)
{
// Place your code here
PORTB = ; //What variable should I call?
delay_ms(3000);
}
}
twi.h
/******************************************************************************
TWI driver library for the CodeVisionAVR C V2.05.1+ Compiler
Copyright (C) 2010-2011 Pavel Haiduc, HP InfoTech S.R.L., All rights reserved.
*******************************************************************************/
#ifndef _TWI_INCLUDED_
#define _TWI_INCLUDED_
#include <stdbool.h>
// TWI transaction result values
#define TWI_RES_OK 0
#define TWI_RES_BUFFER_OVERFLOW 1
#define TWI_RES_ARBITRATION_LOST 2
#define TWI_RES_BUS_ERROR 3
#define TWI_RES_NACK_RECEIVED 4
#define TWI_RES_BUS_TIMEOUT 5
#define TWI_RES_FAIL 6
#define TWI_RES_UNKNOWN 7
extern unsigned char twi_tx_index; // data index in the transmit buffer
extern unsigned char twi_rx_index; // data index in the receive buffer
extern unsigned char twi_result; // holds the result of the last TWI transaction
// TWI master initialization
// bit_rate - SCL bit rate [kHz]
void twi_master_init(unsigned int bit_rate);
// function used for performing a TWI master transaction
// slave_addr - 7 bit address of the TWI slave with which the transaction must be performed
// tx_data - pointer to the buffer that holds the data to be transmitted to the slave
// tx_count - number of bytes that must be transmitted to the slave during the transaction
// rx_data - pointer to the buffer that holds the data received from the slave
// rx_count - number of bytes that must be received from the slave during the transaction
// returns true on success
bool twi_master_trans(
unsigned char slave_addr,
unsigned char *tx_data, unsigned char tx_count,
unsigned char *rx_data, unsigned char rx_count);
// TWI slave initialization
// match_any_addr - if true, the slave match address logic responds to all received addresses
// addr - 7 bit address of the TWI slave
// rx_buffer - pointer to the slave receive buffer
// rx_buffer_size - size of the slave receive buffer
// tx_buffer - pointer to the slave transmit buffer
// slave_rx_handler - pointer to the TWI slave receive processing function
// slave_tx_handler - pointer to the TWI slave transmit processing function
void twi_slave_init(
bool match_any_addr,
unsigned char addr,
unsigned char *rx_buffer,
unsigned char rx_buffer_size,
unsigned char *tx_buffer,
bool (*slave_rx_handler)(bool rx_complete),
unsigned char (*slave_tx_handler)(bool tx_complete)
);
#pragma library twi.lib
#endif
What I want to ask is:
1. After writing to eeprom, what variable should I call to show the bytes on 8 LED?
ex: after writing bytes: 0xF0, then LED in PORTB will be 0xF0 (11110000)
I did search on internet but still confused with this line
twi_master_trans(EEPROM_TWI_BUS_ADDRESS,(unsigned char *) &twi_eeprom,3,0,0);
twi_master_trans(EEPROM_TWI_BUS_ADDRESS,(unsigned char *) &twi_eeprom,2,&eeprom_rd_data,1);
could someone please explain it? what does the &twi_eeprom,3,0,0 actually mean?
Device : Atmega16a
Program : Codevision AVR 3.12
external eeprom : AT24c02b
Any answer and comment would be appreciate.
Thanks and pardon my english.
Ipin
TWI is a method for transferring data both ways from a master device to a slave device. In your case, your code runs on the master, and the EEPROM is the slave. The data moves between the devices at the same time. That is, a byte is transferred to the slave simultaneously to a byte being transferred back from the slave.
The functions given in twi.h describe a way to start this process, and the parameters are described there.
unsigned char slave_addr,
unsigned char *tx_data,
unsigned char tx_count,
unsigned char *rx_data,
unsigned char rx_count
The first parameter is a constant given in your code.
The next two params are the address of the buffer to take data from and the length to take.
The next two are the address of the buffer to put the received data into, and the length.
To write 0x55 to the EEPROM at a specific address, you need to send three bytes to the EEPROM. These are arranged in a struct for you. If you give the function the address of the struct and the length 3, the function will take care of it for you. (unsigned char *) &twi_eeprom is the address of the struct.
You don't care about receiving right now, so just put in 0 and 0 for the address and length to receive.
When you read back the value, you only need to send the address of the byte to the EEPROM. So send the same struct, but only two bytes of it. You also need to save the received byte. It will go into the variable eeprom_rd_data, since you passed the address of that variable into the function. Set PORRTB to equal eeprom_rd_data to display its value.

Trouble in writing to Internal EEPROM- PIC16F684

In a Home security alarm system, we have a remote control armed with PT2440
with Fixed encoding (no hop coding, no encryption/decryption) and a central
receiver system armed with MCU: PIC16F684. I must use the internal EEPROM (256 bytes).
After a lot of programming and testing my problem reduced to: I can write to internal
memory before the main loop, but inside the main while loop, the write operation
failed. Here it is my main code
//This function Writes data to given address in internal EEPROM of PIC MCU
void internal_EEPROM_putc(unsigned char addr, unsigned char data)
{
unsigned char INTCON_SAVE;
EEADR = addr;
EEDATA = data;
EEPGD = 0; // 0 = Access data EEPROM memory
WREN = 1; // enable writes to internal EEPROM
INTCON_SAVE = 0x9B; // Save INTCON register contants
GIE = 0; // Disable interrupts, Next two lines SHOULD run without
// interrupts
EECON2=0x55;
EECON2=0xAA;
WR = 1; // begin write to internal EEPROM
INTCON = INTCON_SAVE; //Now we can safely enable interrupts if previously used
delay_cycles(1); // like NOP
while(!WR) // Wait till write operation complete
delay_cycles(1);
WREN=0; // Disable writes to EEPROM on write complete (EEIF flag on set PIR2 )
}
// This function reads data from address given in internal EEPROM of PIC
unsigned char internal_EEPROM_getc(unsigned char addr)
{
EEADR = addr;
EEPGD= 0; // 0 = Access data EEPROM memory
RD = 1; // EEPROM Read
return EEDATA; // return data
}
void main()
{
// IT WORKS!
internal_EEPROM_putc(0x12,0x34); //Write 0x34 to EEPROM address 0x12
delay_cycles(1);
c = internal_EEPROM_getc(0x12); // Read EEPROM address 0x12 in to variable C
if (c != 0x34) {
RC1 = ON; // activate a relay, if read and write mismatches
delay_ms(500);
RC1 = OFF;
} // there is no relay activation
while (TRUE) {
// IT DOESN'T WORK!
internal_EEPROM_putc(0x13,0x56); //Write 0x34 to EEPROM address 0x12
delay_cycles(1);
c = internal_EEPROM_getc(0x13); // Read EEPROM address 0x12 in to variable C
if (c != 0x56) {
RC1 = ON;
delay_ms(500);
RC1 = OFF;
} // no relay activation
}
}
Any thoughts?
FYI, I use C programming language (not assembly), I use CCS C compiler (PCWHD) (4.057)
under Windows 7 (32 and 64 bits) and my programmer is PICKKit 2).

How do you write and read to memory with PIC18?

I want to store a number to PIC18 then retain it even if the power is lost or the unit is reset. I think my writing code portion looks fine, just the reading portion of it looks strange after the unit is reset.
I am using the following code which I got from Microchip.
Code:
unsigned int value;
unsigned int DEEdata = 1;
unsigned int DEEaddr = 0x04;
DataEEInit();
dataEEFlags.val = 0;
DataEEWrite(DEEdata,DEEaddr);
value = DataEERead(DEEaddr);
Nop();
printf("%d",value);
The ouput: 1
However when I reset the unit and only use the reading code I always get 255.
Code to read:
DataEEInit();
value = DataEERead(DEEaddr);
printf("%d",value);
The output: 255
Why is this happening? I am assuming maybe the value is not being saved or the reading portion is incorrect. Thank you!
Two functions: write to flash using 64-byte buffer # 8-byte blocks and a read/compare flash function.
For device: PIC18F46K80
Stuff for a header file:
#define PRGM_BUFFER_SIZE 8
#define TABLE_WRITE_SIZE 64
#define LOAD_TBL_PTR(x) { TBLPTRU = ((((x)>>8)>>8)&0xff);\
TBLPTRH = (((x) >> 8) & 0xff);\
TBLPTRL = ((x) & 0xff);\
}
Write to flash function:
/******************************************************
* Function : write_block
* Input : uint16_t position in destination flash
* Global : uint8_t buffer[64] - Location of source data
* Output : None
* Description : Writes the contents of the 64 byte
* data buffer to program flash space. Only 64 bytes
* can be written at once. The process of writing
* to flash is: Erase->Write.
******************************************************/
static void write_block(uint16_t addr)
{
int r, c;
// Erase flash block first. Erases a 64 byte block at a time.
LOAD_TBL_PTR(addr);
EECON1bits.EEPGD = 1; // Point to flash program memory
EECON1bits.CFGS = 0; // Access flash memory
EECON1bits.WREN = 1; // Enable write to memory
EECON1bits.FREE = 1; // Enable Erase operation
EECON2 = 0x55;
EECON2 = 0xAA;
EECON1bits.WR = 1; // Clear the flash
asm("NOP"); // Stall
// Write buffer to internal buffer. This process writes 8 bytes at a time
// so we need to loop 8 times (8*8 = 64).)
for (r = 0; r < 8; r++)
{
LOAD_TBL_PTR((addr + (r * 8)));
for (c = 0; c < PRGM_BUFFER_SIZE; c++)
{
TABLAT = buffer[(r * 8) + c];
asm("TBLWT*+"); // Push byte and then inc to next internal buffer cell
}
// Write the block to flash
asm("TBLRD*-"); // Point back to original row
// Write internal buffer to flash
EECON1bits.EEPGD = 1; // Point to flash program memory
EECON1bits.CFGS = 0; // Access flash program memory
EECON1bits.WREN = 1; // Enable write to memory
INTCONbits.GIE = 0; // Disable interrupts
EECON2 = 0x55;
EECON2 = 0xAA;
EECON1bits.WR = 1; // Start programming flash
INTCONbits.GIE = 1; // Re-enable interrupts
EECON1bits.WREN = 0; // Disable write to memory
}
}
Verify written data (demonstrates flash read)
/******************************************************
* Function : compare_block
* Input : uint16_t position in destination flash
* Global : uint8_t buffer[64] - Location of previous written data
* Output : bool true=successful, false=did not match
* Description : Reads a 64 byte block of flash memory and
* compares it to the data found in the global buffer.
******************************************************/
static bool compare_block(uint16_t addr)
{
bool retVal = true; // succeeds
uint8_t i = 0;
INTCONbits.GIE = 0; // Disable interrupts
LOAD_TBL_PTR(addr);
for (i = 0; i < TABLE_WRITE_SIZE && retVal == true; i++)
{
asm("TBLRD*+");
if (buffer[i] != TABLAT)
retVal = false;
}
INTCONbits.GIE = 1; // Enable interrupts
return retVal;
}
Yours,
Bryan Wilcutt
The device you're using doesn't have internal non-volatile memory apart from its Flash, generally used for storing code.
You have two options that I can see:
Use some external Flash or EEPROM and interface it to the External Memory Bus that's available on this PIC (see page 97 of the Family Datasheet).
Remap the internal Flash to reserve a small portion that can be used for storing your data (so that it doesn't interfere with the memory area used exclusively for code) and write your data into this region (page 87).
I haven't worked with PICs for years, so can't offer you much in the way of implementation detail but I suspect there are many examples you can source from Microchip's website.
In essence, the reason your code doesn't work is because you're trying to access memory that isn't there. If it is there, then the interface is not correct.
EDIT:
I've had a look through the code examples page for the PIC18 on Microchip's website and can't find any C examples for writing to the program memory. Unfortunately, it looks like you'll have to implement it in assembler. I don't know the semantics for the MPLAB compiler but, generally, it'll be something like this if you're going to do it inline:
void my_assembler_function(void)
{
// Inline assembler code, actioned via C.
asm("MOV x y");
asm("MOV y z");
}
Alternatively, many C compilers for microprocessor's allow you to call an external .s file with a C function call, saving you from doing it inline.
I think you can follow the example I found here to actually implement the functionality you're after.
SRAM can not be used to store Non-volatile data...
SRAM will loose data during power cycle...
Options:
1. Use internal EEPROM if available.
2. External EEPROM through I2C or SPI.
3. PIC18 Data Emulation Library.
This is an explanation of the PIC18:
/* EEPROM Read and Write Functions -- WORKING
* Used PIC18F45K22 and MPLAB and C18
* Read and Write functions work.
* EEPROM has 256 bytes of memory (256 distinct characters)
* Select "Window" -> "PIC Memory Views" -> "EE Data Memory"
* Download program to PIC18
* Hold PIC in Reset (circle arrow with pause button)
* Open EE Data Memory Tab and click "Read Device Memory" button (Top left of EE Data tab) while PIC is held in Reset
*/
This is helpful code:
#include <p18cxxx.h>
#include <p18f45k22.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#pragma config FOSC = INTIO67, PLLCFG = OFF, PRICLKEN = ON, FCMEN = ON, PWRTEN = OFF
#pragma config BOREN = SBORDIS, BORV = 250, WDTEN = OFF, WDTPS = 2048, PBADEN = OFF, WRTD = OFF
#pragma config HFOFST = OFF, MCLRE = EXTMCLR, STVREN = ON, LVP = OFF, DEBUG = ON, CPD = OFF
void EE_Write(unsigned char addr, unsigned char value);
unsigned char EE_Read(unsigned char addr);
unsigned char test;
void main(void){
OSCTUNEbits.PLLEN = 1;
OSCCON = 0x4C; //Set to use internal clock.
OSCCON2 = 0x00; // No 4x PLL
TRISB = 0x00;
ANSELB = 0x00;
PORTB = 0x00;
EE_Write(05, 0x5A);
Delay10KTCYx(50);
test = EE_Read(05);
Delay10KTCYx(50);
PORTB = 0xFF;
Delay10KTCYx(50);
PORTB = 0x00;
}
void EE_Write(unsigned char addr, unsigned char value)
{
unsigned char SaveGIE = 0;
// Set EEPROM address
EEADR = addr%256;
// Set EEPROM data
EEDATA = value;
// Select Data
EECON1bits.EEPGD = 0;
// Select EEPROM
EECON1bits.CFGS = 0;
// Enable write
EECON1bits.WREN = 1;
// Save current global interrupt enable state
SaveGIE = INTCONbits.GIE;
// Disable interrupts
INTCONbits.GIE = 0;
// Write unlock sequence
EECON2 = 0x55;
EECON2 = 0xaa;
// Start write
EECON1bits.WR = 1;
// Restore previous interrupts enable state
INTCONbits.GIE = SaveGIE;
// Wait for write completion
while(EECON1bits.WR);
// Disable writes
EECON1bits.WREN = 0;
}
unsigned char EE_Read(unsigned char addr){
while(EECON1bits.RD || EECON1bits.WR); // check the WR&RD bit to see if a RD/WR is in progress
EEADR = addr; // Write the address to EEADR.
EECON1bits.CFGS = 0;
EECON1bits.EEPGD = 0;
EECON1bits.RD = 1; // Set the RD bit to trigger the eeprom read operation.
return(EEDATA);
}
Some PIC18 micros have an internal EEPROM in addition to the internal flash. The 18F87J11 does not have this so you have 2 options:
1) Write to the flash memory - this is where your program is stored. make sure the number of write/read cycles is ok for your application.
2) Use an external i2c or spi memory for your configuration settings
The DataEEWrite you are using are from an 'eeprom emulation' library from microchip (linked in the comments below. There are a couple of things to be careful of:
Watch out when reprogramming the flash! you might overwrite your settings
Remember it isn't really eeprom! The write cycles are limited and you have to erase big sections of memory - you can't erase a single byte
The value of 255 is default value for EEPROM memory. I think after changing the code, you program microcontroller IC again. So, your EEPROM memory will be erased and return to its default value. If you use MPLAB as compiler, you can go to 'Programmer'tab > Settings.. > Program Memory > Program Options and click on Preserve EEPROM on Program.
Hope it works.
To retain the values on power cycle, SRAM memory should be used. Please confirm if you have SRAM memory available first.

Resources