Author Topic: can't write twice to EEPROM on PIC16F18323  (Read 276 times)

0 Members and 1 Guest are viewing this topic.

Offline FrankBuss

  • Supporter
  • ****
  • Posts: 1842
  • Country: de
    • Frank Buss
can't write twice to EEPROM on PIC16F18323
« on: January 14, 2018, 10:30:16 AM »
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
A single EEPROM byte is written with NVMDATA. The operation includes an implicit erase cycle for that byte (it is not necessary to set the FREE bit), and requires many instruction cycles to finish.

"many" is specified later in the datasheet, can be max 5 ms. The full project is here. 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: [Select]
EEPROM test start
expected: 92, read: 92
expected: f7, read: f7
expected: 00, read: 00
expected: 00, read: 00
expected: 92, read: 00
expected: f7, read: 00
EEPROM test end

After one or more resets, you can see this output:

Code: [Select]
EEPROM test start
expected: 92, read: 00
expected: f7, read: 00
expected: 00, read: 00
expected: 00, read: 00
expected: 92, read: 00
expected: f7, read: 00
EEPROM test end

This is the source code of the main.c from the test project:

Code: [Select]
#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;
}

Online cv007

  • Regular Contributor
  • *
  • Posts: 157
Re: can't write twice to EEPROM on PIC16F18323
« Reply #1 on: January 14, 2018, 11:26:24 AM »
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)
« Last Edit: January 14, 2018, 11:59:43 AM by cv007 »
 

Offline FrankBuss

  • Supporter
  • ****
  • Posts: 1842
  • Country: de
    • Frank Buss
Re: can't write twice to EEPROM on PIC16F18323
« Reply #2 on: January 14, 2018, 11:52:26 AM »
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.
 
The following users thanked this post: jancumps

Online cv007

  • Regular Contributor
  • *
  • Posts: 157
Re: can't write twice to EEPROM on PIC16F18323
« Reply #3 on: January 14, 2018, 12:07:44 PM »
Quote
It works when writing from 0x7000 to 0x70ff
The 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).
 

Offline FrankBuss

  • Supporter
  • ****
  • Posts: 1842
  • Country: de
    • Frank Buss
Re: can't write twice to EEPROM on PIC16F18323
« Reply #4 on: January 14, 2018, 12:40:08 PM »
Quote
It works when writing from 0x7000 to 0x70ff
The 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).

Do 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.

Online cv007

  • Regular Contributor
  • *
  • Posts: 157
Re: can't write twice to EEPROM on PIC16F18323
« Reply #5 on: January 14, 2018, 01:38:03 PM »
Quote
Do you mean the same table?
No, I mean the one I got directly from Microchips web page for 16F18323. See attached picture.
http://www.microchip.com/wwwproducts/en/PIC16F18323

Quote
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.

which is why I wrote-
Quote
(although they may have read/write info incorrect in some cases)
this is one case, you can write to user id via nvm

this is what I use to write to user id (no flash write needed in this case)-
https://gist.github.com/cv007/ef4c71befc9fffeec106baac3d9c2848
« Last Edit: January 14, 2018, 01:44:55 PM by cv007 »
 

Offline FrankBuss

  • Supporter
  • ****
  • Posts: 1842
  • Country: de
    • Frank Buss
Re: can't write twice to EEPROM on PIC16F18323
« Reply #6 on: January 14, 2018, 01:53:14 PM »
Quote
Do you mean the same table?
No, I mean the one I got directly from Microchips web page for 16F18323. See attached picture.
http://www.microchip.com/wwwproducts/en/PIC16F18323

They 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 important :scared: But you are right, probably the most significant bit is not used anyway.

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 3937
  • Country: gb
Re: can't write twice to EEPROM on PIC16F18323
« Reply #7 on: January 15, 2018, 12:08:30 AM »
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: [Select]

// 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 ID
   NVMCON1bits.WREN=1;
   
   NVMADRL=(uint8_t)u16Addr;
   NVMADRH=(uint8_t)(u16Addr>>8);
   NVMDATL=u8Data;
   
   bGIESave=INTCONbits.GIE; // Save interrupt enable state before disabling interrupts
   INTCONbits.GIE=0;
   
   // Unlock sequence
   NVMCON2=0x55;
   NVMCON2=0xAA;
   NVMCON1bits.WR=1; // Initiate write
   
   INTCONbits.GIE=bGIESave; // Restore interrupt enable state
   
   while (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 ID
   NVMCON1bits.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[8]={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[0]=NVMEERead(0xF000);
    au8[1]=NVMEERead(0xF001);
    au8[2]=NVMEERead(0xF002);
    au8[3]=NVMEERead(0xF003);
   
    NOP();
   
    // Access using XC8's code

    eeprom_write(0x04,0x57);
    eeprom_write(0x05,0xA8);
    eeprom_write(0x06,0xB9);
    eeprom_write(0x07,0x5A);
   
    au8[0]=eeprom_read(0x00);
    au8[1]=eeprom_read(0x01);
    au8[2]=eeprom_read(0x02);
    au8[3]=eeprom_read(0x03);
    au8[4]=eeprom_read(0x04);
    au8[5]=eeprom_read(0x05);
    au8[6]=eeprom_read(0x06);
    au8[7]=eeprom_read(0x07);
   
    NOP();
   
    while (1)
    {
        LATA=(uint8_t)~LATA;
    }
    return 0;
}

 

Offline FrankBuss

  • Supporter
  • ****
  • Posts: 1842
  • Country: de
    • Frank Buss
Re: can't write twice to EEPROM on PIC16F18323
« Reply #8 on: January 15, 2018, 12:41:46 AM »
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.

Online cv007

  • Regular Contributor
  • *
  • Posts: 157
Re: can't write twice to EEPROM on PIC16F18323
« Reply #9 on: January 15, 2018, 01:16:54 AM »
I find writing your own macros is easier, and can use them mostly unchanged from chip to chip

baud-
https://gist.github.com/cv007/9459f8d0d99988b92ae46a8804dd7567
or 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/853d29f6972dd3758f982bb8b1809f38


Clc 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.hpp
but figuring out  how to get what you want requires some thinking whether you have a code generator or not

if anyone can make use of MCC, fine by me, I just can't (yet)
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 3937
  • Country: gb
Re: can't write twice to EEPROM on PIC16F18323
« Reply #10 on: January 15, 2018, 01:21:24 AM »
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.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf