can't write twice to EEPROM on PIC16F18323 - Page 1
Forum section: electronics / general

author: FrankBuss
author_rank: Unknown
timestamp: January 13, 2018, 11:30:16 pm
content: I wrote a simple test program with Code Configurator generated code (really useful, makes PIC coding much easier), but I can't write twice to an EEPROM location, looks like the previous byte is not erased. But the datasheet says this:Quote"many" is specified later in the datasheet, can be max 5 ms. The full project ishere. I'm using MPLABX 4.05. Tested with external 5V power, and proper 100 nF decoupling capacitor near VDD/VSS. And it has an external 8 MHz digital clock connected to pin 2, RA5. If you connect an UART receiver to pin 9, RC1, 115200 baud, 8N1, you can see this output after programming:Code:EEPROM test startexpected: 92, read: 92expected: f7, read: f7expected: 00, read: 00expected: 00, read: 00expected: 92, read: 00expected: f7, read: 00EEPROM test endAfter one or more resets, you can see this output:Code:EEPROM test startexpected: 92, read: 00expected: f7, read: 00expected: 00, read: 00expected: 00, read: 00expected: 92, read: 00expected: f7, read: 00EEPROM test endThis is the source code of the main.c from the test project:Code:#define _XTAL_FREQ 32000000#include <stdint.h>#include "mcc.h"void sendHex(uint8_t b){const char* digits = "0123456789abcdef";EUSART_Write(digits[b>>4]);EUSART_Write(digits[b&0xf]);}void sendString(char* s){while (*s) {EUSART_Write(*s);s++;}}void newline(){EUSART_Write(0x0d);EUSART_Write(0x0a);}void testAdr(uint8_t adr, uint8_t b){DATAEE_WriteByte(adr, b);sendString("expected: ");sendHex(b);sendString(", read: ");sendHex(DATAEE_ReadByte(adr));newline();}int main(){SYSTEM_Initialize();__delay_ms(1000);newline();sendString("EEPROM test start");newline();testAdr(0, 0x92);testAdr(1, 0xf7);testAdr(0, 0x00);testAdr(1, 0x00);testAdr(0, 0x92);testAdr(1, 0xf7);sendString("EEPROM test end");newline();while (1);return 0;}

author: cv007
author_rank: Frequent Contributor
timestamp: January 14, 2018, 12:26:24 am
content: eeprom is at 0xF000-0xF0FF, you are reading/writing user id locations it would seem (which requires row erase- I'm sure it all figures out when you take into account no erasing is taking place on those user id bytes)there is a table in the datasheet that shows nvm address organization (although they may have read/write info incorrect in some cases)this is one reason I dislike code generators, they sometimes make no sense- they have a specific function name that implies reading/writing an eeprom byte- now why does one have to specify the actual eeprom address (0xF0xx) when the function knows that the only thing you are reading/writing is eeprom, so why not use 0-255? If not, then why not combine the read functions with the other types (flash, user id, config bits)

author: FrankBuss
author_rank: Unknown
timestamp: January 14, 2018, 12:52:26 am
content: Thanks, I expected the address to be relative. It works when writing from 0x7000 to 0x70ff, as specified in table 11-2, NVM ORGANIZATION AND ACCESS INFORMATION, in the datasheet.

author: cv007
author_rank: Frequent Contributor
timestamp: January 14, 2018, 01:07:44 am
content: QuoteThe table shows using FSR for reads use that address, and 0xF000-0xF0FF for NVM read/write, but that upper bit may not matter (I would probably use the correct address anyway).

author: FrankBuss
author_rank: Unknown
timestamp: January 14, 2018, 01:40:08 am
content: Quote from: cv007 on January 14, 2018, 01:07:44 amDo you mean the same table? I don't see any 0xf000-0xf0ff region for EEPROM access. Memory type EEPROM and "User Memory" is 0x7000-0x70ff, both for NVMADR and FSR access:BTW, it was interesting that I could write to "User ID". The table says for "allowed operations" only READ. I could even erase this region, with the FREE bit.

author: cv007
author_rank: Frequent Contributor
timestamp: January 14, 2018, 02:38:03 am
content: QuoteNo, I mean the one I got directly from Microchips web page for 16F18323. See attached picture.http://www.microchip.com/wwwproducts/en/PIC16F18323Quotewhich is why I wrote-Quotethis is one case, you can write to user id via nvmthis is what I use to write to user id (no flash write needed in this case)-https://gist.github.com/cv007/ef4c71befc9fffeec106baac3d9c2848

author: FrankBuss
author_rank: Unknown
timestamp: January 14, 2018, 02:53:14 am
content: Quote from: cv007 on January 14, 2018, 02:38:03 amThey changed it. I have a local copy of the datasheet, revision C, where it is the address 0x7000, and in revision D it is 0xf000. You can see this in appendix A, data sheet revision history, table 11-2 was updated. Nothing importantBut you are right, probably the most significant bit is not used anyway.

author: Howardlong
author_rank: Super Contributor
timestamp: January 14, 2018, 01:08:30 pm
content: Is there a reason not to use XC8's own eeprom_read & eeprom_write? Alternatively, use your own code. Here's mine, admittedly for the PIC16F18313 rather than the '323, I don't have any '323s in stock, put it shares the same datasheet as the '313.I am with cv007 on the use of code generators, I've wasted far too much time second guessing the generated code, it's not maintainable, often doesn't perform well, it's frequently bug ridden, and it forces you into a code strait jacket. You have to know your way around the datasheet whether you use MCC or not. Distributing code for third party analysis is a PITA too, half a dozen files for a blinky discourages help, that is hardly progress in my book.Code:// PIC16F18313 Configuration Bit Settings// 'C' source line config statements// CONFIG1#pragma config FEXTOSC = OFF // FEXTOSC External Oscillator mode Selection bits (Oscillator not enabled)#pragma config RSTOSC = HFINT1 // Power-up default value for COSC bits (HFINTOSC (1MHz))#pragma config CLKOUTEN = ON // Clock Out Enable bit (CLKOUT function is enabled; FOSC/4 clock appears at OSC2)#pragma config CSWEN = OFF // Clock Switch Enable bit (The NOSC and NDIV bits cannot be changed by user software)#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)// CONFIG2#pragma config MCLRE = ON // Master Clear Enable bit (MCLR/VPP pin function is MCLR; Weak pull-up enabled )#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)#pragma config WDTE = OFF // Watchdog Timer Enable bits (WDT disabled; SWDTEN is ignored)#pragma config LPBOREN = OFF // Low-power BOR enable bit (ULPBOR disabled)#pragma config BOREN = OFF // Brown-out Reset Enable bits (Brown-out Reset disabled)#pragma config BORV = LOW // Brown-out Reset Voltage selection bit (Brown-out voltage (Vbor) set to 2.45V)#pragma config PPS1WAY = OFF // PPSLOCK bit One-Way Set Enable bit (The PPSLOCK bit can be set and cleared repeatedly (subject to the unlock sequence))#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a Reset)#pragma config DEBUG = OFF // Debugger enable bit (Background debugger disabled)// CONFIG3#pragma config WRT = OFF // User NVM self-write protection bits (Write protection off)#pragma config LVP = OFF // Low Voltage Programming Enable bit (HV on MCLR/VPP must be used for programming.)// CONFIG4#pragma config CP = OFF // User NVM Program Memory Code Protection bit (User NVM code protection disabled)#pragma config CPD = OFF // Data NVM Memory Code Protection bit (Data NVM code protection disabled)// #pragma config statements should precede project file includes.// Use project enums instead of #define for ON and OFF.#include <xc.h>#include <stdint.h>#include <stdbool.h>static void NVMEEWrite(uint16_t u16Addr,uint8_t u8Data){bool bGIESave;while (NVMCON1bits.WR) // Wiat in case any outstanding writes in progess{NOP();}NVMCON1bits.NVMREGS=1; // 1 => EEPROM, Config, user/dev IDNVMCON1bits.WREN=1;NVMADRL=(uint8_t)u16Addr;NVMADRH=(uint8_t)(u16Addr>>8);NVMDATL=u8Data;bGIESave=INTCONbits.GIE; // Save interrupt enable state before disabling interruptsINTCONbits.GIE=0;// Unlock sequenceNVMCON2=0x55;NVMCON2=0xAA;NVMCON1bits.WR=1; // Initiate writeINTCONbits.GIE=bGIESave; // Restore interrupt enable statewhile (NVMCON1bits.WR) // Wait for completion{NOP();}NVMCON1bits.WREN = 0; // Disable further writing}static uint8_t NVMEERead(uint16_t u16Addr){while (NVMCON1bits.WR) // Wait in case any outstanding writes in progress{NOP();}NVMCON1bits.NVMREGS=1; // 1 => EEPROM, Config, user/dev IDNVMCON1bits.WREN=1;NVMADRL=(uint8_t)u16Addr;NVMADRH=(uint8_t)(u16Addr>>8);NVMCON1bits.RD=1; // Initiate the read, results on PIC16F183x3 available immediately after, some other devices require short NOP delays.return NVMDATL;}int main(void){static volatile uint8_t au8={0,0,0,0,0,0,0,0};LATA=0;TRISA=0;ANSELA=0;// Note that the debugger does not refresh its copy of the NVM area, we need to copy it to RAM and look at it there// Access using "own code" (above)NVMEEWrite(0xF000,0x56);NVMEEWrite(0xF001,0xA7);NVMEEWrite(0xF002,0xB8);NVMEEWrite(0xF003,0x59);au8=NVMEERead(0xF000);au8=NVMEERead(0xF001);au8=NVMEERead(0xF002);au8=NVMEERead(0xF003);NOP();// Access using XC8's codeeeprom_write(0x04,0x57);eeprom_write(0x05,0xA8);eeprom_write(0x06,0xB9);eeprom_write(0x07,0x5A);au8=eeprom_read(0x00);au8=eeprom_read(0x01);au8=eeprom_read(0x02);au8=eeprom_read(0x03);au8=eeprom_read(0x04);au8=eeprom_read(0x05);au8=eeprom_read(0x06);au8=eeprom_read(0x07);NOP();while (1){LATA=(uint8_t)~LATA;}return 0;}

author: FrankBuss
author_rank: Unknown
timestamp: January 14, 2018, 01:41:46 pm
content: I didn't know the eeprom_read and eeprom_write functions, was the first time I used the EEPROM in a PIC. The functions I used were generated by the Code Configurator (there is a checkbox in the memory component to generate the code for it).Usually I don't like code generators either, but I like the Code Configurator, because it is much faster to initialize the peripherals with it (coding time, not runtime). I agree that you still have to read the datasheet, but you don't have to figure out how the bits are named and which registers you have to set. And especially with CLC, there is no way to do this easily by hand what you can do with the visual editor with the gate diagrams.And it shows you warnings, if you do something stupid, like setting a pin to input, but it has to be output because of the peripheral that uses it etc. If you set the registers manually, you can do all kind of undefined stuff, if you are not very careful. Or for the UART, you can just enter the desired baud rate, and it figures out how to set the registers, and shows you the error in percent. No need anymore to manually enter the formula or using a spreadsheet program to calculate it.I treat it just like another compiler layer. It is the same with C: usually you don't care about the assembler that it generates, and so I don't care about the MCC functions. And the architecture with separate files is better than with some other code generators, with special blocks, marked by comment start/end lines, where you have to write your code between and all over the place, like with CubeX. The MCC generated files are cleanly separated from your source code and only one include and init call from your main file. And so far I didn't have problems with bugs with it.

author: cv007
author_rank: Frequent Contributor
timestamp: January 14, 2018, 02:16:54 pm
content: I find writing your own macros is easier, and can use them mostly unchanged from chip to chipbaud-https://gist.github.com/cv007/9459f8d0d99988b92ae46a8804dd7567or a simple calculator and 15 seconds (how many baud rates and crystal freqs does one actually use? for me there are not that many combinations, so could also have a simple little table with most used combinations)pins/pps-https://gist.github.com/cv007/853d29f6972dd3758f982bb8b1809f38Clc may be a different story, although the problem is not how to hit the right bits, but WHICH bits to hit to get what you want (maybe they have the clc special tool inside that they used to have separately, don't know).for pic32mm, hitting the bits is not hard-https://github.com/cv007/PIC32MM_Curiosity_CPP/blob/master/Clc.hppbut figuring out how to get what you want requires some thinking whether you have a code generator or notif anyone can make use of MCC, fine by me, I just can't (yet)

author: Howardlong
author_rank: Super Contributor
timestamp: January 14, 2018, 02:21:24 pm
content: I think you’ve been lucky, pretty much every time I’ve used MCC I’ve given up with it after finding yet another bug.You are correct about the CLC, it does benefit from a gui, this was available as a standalone gui app at one point.Some further issues of these code generators is they frequently lack backwards compatibility, and break old projects. As the version’s tied to your development IDE, you risk breaking your older projects every time you uodate MCC, and they regularly release new versions. Pretty much every newly added device added to MCC has a number of bugs in my experience, often proving that they’d never tested it on real hardware, as even so,ething as fundamental as clock generation often doesn’t work.It also somewhat forces top-down development, i.e. you need to know exactly how you’re going to use the device ahead of time in its enirety, because adding on functionality incrementally often breaks things unexpectedly.This is where it differs from the compiler tool chain. It’s unusual to get regression on an updated compiler toolchain, and when it happens it’s usually localised and reasonably easy to correct. With MCC, it’s not really mature enough to trust it that it won’t break existing projects that’ll mean a project rethink.