Hot!EEPROM read routine interferes with LCD write

Page: 123 > Showing page 1 of 3
Author
Trackhappy
Starting Member
  • Total Posts : 51
  • Reward points : 0
  • Joined: 2016/11/03 16:07:08
  • Location: 0
  • Status: offline
2018/12/25 22:08:03 (permalink)
0

EEPROM read routine interferes with LCD write

Hi all. Fairly new to coding, so please be gentle. :)
So, Pic18F26K40 Rev. a043, XC8 2.00 free version, MPLab X 5.05 (5.10 has a PICK Kit3 bug).
 
The project is a pump controller and i need to store some parameters in EEPROM. 16 x 2 LCD display works perfectly on its own (displaying various system variables and states)  without EEPROM read.
Problem: As soon as I do a "Byte Read" the display does not display anything further. If I comment out the Byte Read in main, it continues to display its next test Message "Ready 2". Relay = 1; still works (LED on there), so the code is moving on ok.
 
If I remove the display code and go into debug the Byte Read works ok and hovering over ROMData gives the correct value. 
 
Is there something I am not telling the compiler and the two are overwriting memory locations maybe? I am stumped.
 
Code below. I have stripped out the main functionality, this is just config, lcd and EEPROM code which shows the problem.
 
Thanks in advance and hope everybody had a great Christmas.
 
main.c:
// 18F26K40 Configuration Bit Settings

// CONFIG1L
#pragma config FEXTOSC = OFF // ->External Oscillator not enabled
#pragma config RSTOSC = HFINTOSC_64MHZ // ->HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
// CONFIG1H
#pragma config CLKOUTEN = OFF // ->CLKOUT function is disabled
#pragma config CSWEN = ON // ->Writing to NOSC and NDIV is allowed
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit->Fail-Safe Clock Monitor disabled

// CONFIG2L
#pragma config MCLRE = EXTMCLR // ->If LVP = 0, MCLR pin is MCLR; If LVP = 1, RE3 pin function is MCLR
#pragma config PWRTE = OFF // Power-up Timer Enable bit->Power up timer disabled
#pragma config LPBOREN = OFF // ->ULPBOR disabled
#pragma config BOREN = OFF // Brown-out Reset Enable bits->Brown-out Reset disabled

// CONFIG2H
#pragma config BORV = VBOR_2P45 // Brown Out Reset Voltage selection bits->Brown-out Reset Voltage (VBOR) set to 2.45V
#pragma config ZCD = OFF // ZCD Disable bit->ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
#pragma config PPS1WAY = ON // PPSLOCK bit One-Way Set Enable bit->PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle
#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit->Stack full/underflow will cause Reset
#pragma config DEBUG = OFF // Debugger Enable bit->Background debugger disabled
#pragma config XINST = OFF // Extended Instruction Set Enable bit->Extended Instruction Set and Indexed Addressing Mode disabled

// CONFIG3L
#pragma config WDTCPS = WDTCPS_31 // ->Divider ratio 1:65536; software control of WDTPS
#pragma config WDTE = OFF // WDT operating mode->WDT Disabled

// CONFIG3H
#pragma config WDTCWS = WDTCWS_7 // WDT Window Select bits->window always open (100%); software control; keyed access not required
#pragma config WDTCCS = SC // WDT input clock selector->Software Control

// CONFIG4L
#pragma config WRT0 = OFF // Write Protection Block 0->Block 0 (000800-003FFFh) not write-protected
#pragma config WRT1 = OFF // Write Protection Block 1->Block 1 (004000-007FFFh) not write-protected
#pragma config WRT2 = OFF // Write Protection Block 2->Block 2 (008000-00BFFFh) not write-protected
#pragma config WRT3 = OFF // Write Protection Block 3->Block 3 (00C000-00FFFFh) not write-protected

// CONFIG4H
#pragma config WRTC = OFF // Configuration Register Write Protection bit->Configuration registers (300000-30000Bh) not write-protected
#pragma config WRTB = OFF // Boot Block Write Protection bit->Boot Block (000000-0007FFh) not write-protected
#pragma config WRTD = OFF // Data EEPROM Write Protection bit->Data EEPROM not write-protected
#pragma config SCANE = ON // ->Scanner module is available for use, SCANMD bit can control the module
#pragma config LVP = ON // Low Voltage Programming Enable bit->HV on MCLR/VPP must be used for programming

// CONFIG5L
#pragma config CP = OFF // UserNVM Program Memory Code Protection bit->UserNVM code protection disabled
#pragma config CPD = OFF // DataNVM Memory Code Protection bit->DataNVM code protection disabled

// CONFIG6L
#pragma config EBTR0 = OFF // Table Read Protection Block 0->Block 0 (000800-003FFFh) not protected from table reads executed in other blocks
#pragma config EBTR1 = OFF // Table Read Protection Block 1->Block 1 (004000-007FFFh) not protected from table reads executed in other blocks
#pragma config EBTR2 = OFF // Table Read Protection Block 2->Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks
#pragma config EBTR3 = OFF // Table Read Protection Block 3->Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks

// CONFIG6H
#pragma config EBTRB = OFF // Boot Block Table Read Protection bit->Boot Block (000000-0007FFh) not protected from table reads executed in other blocks


#include <xc.h> /* XC8 General Include File */
#include <stdint.h> /* For uint8_t definition */
#include <stdbool.h> /* For true/false definition */
#include <stdio.h>
#include "lcd.h"


//__EEPROM_DATA (0x60,0x78,0x0A,0x78,0x0A,0x05,0xF0,0x36);//EEPROM default entries addr 00
//__EEPROM_DATA (0x46,0x0F,0x00,0x1E,0x00,0x00,0x00,0xDD);//EEPROM default entries addr 08



#define _XTAL_FREQ 64000000 //Define 64Mb used for __delay_()



//Prod - #define WarnLight LATCbits.LATC3 //Warning relay output
#define Relay LATCbits.LATC3 //Relay control output

/****************** PIN Mapping *******************/
#define RS LATCbits.LATC5
#define RW LATCbits.LATC6
#define EN LATCbits.LATC7
#define BF PORTBbits.RB7
#define DATAPORT LATB



/************** Line Addr Mapping ******************/
#define LCD_LINE1 0x80
#define LCD_LINE2 0xC0
#define LCD_LINE3 0x94
#define LCD_LINE4 0xD4

#define CLRSCR 0x01
#define DISPLAY_ON 0x0C
#define DISPLAY_OFF 0x08
#define DISPLAY_HOME 0x02
#define CURSOR_ON 0x0A
#define CURSOR_OFF 0x08
#define CURSOR_INC 0x06
#define MODE_8BIT 0x38
#define MODE_4BIT 0x28



/******************************************************************************/
/* User Global Variable Declaration */
/******************************************************************************/

void PLL_Init();
void TIMER_Init();
void PIN_Init();
void ADC_Init();

void Byte_read();

//global variables

unsigned char secondspulse;
unsigned char Second;
unsigned char MinuteCounter; //To calculate minutes for recovery timer
unsigned char Addr0F;
unsigned char ROMData;
unsigned int Milliseconds;
unsigned int Minutes; //Count minutes


bool SampleTime; //500mS timer event trigger


             //Runtime is zero - no water or pump issue


void PLL_Init()//Set up PLL for 64 MHz operation, enable secondary 32Khz oscillator (for Timer0)
{
    OSCCON1 = 0x60; // NOSC HFINTOSC; NDIV 1;
    OSCCON3 = 0b01000000; // CSWHOLD may proceed; SOSCPWR High power;
    OSCEN = 0x08; // MFOEN disabled; LFOEN disabled; ADOEN disabled; SOSCEN enabled; EXTOEN disabled; HFOEN disabled;
    OSCFRQ = 0x08; // HFFRQ 64_MHz;
    OSCTUNE = 0x00; // TUN 0;
}

void TIMER_Init(void)
{
    //TMR0 8 bit, Prescaler 1:1, Preload TMR0H 20 = 1mS
   T0CON0bits.T0EN = 0; //Stop timer0 while we setup parameters
   PIE0bits.TMR0IE = 1; //Enable Timer0 Interrupts
   T0CON1bits.T0CS = 5; //2 FOSC/4 as source (16Mhz))
   T0CON0bits.T016BIT = 0; //Set timer0 as 8 bit
   T0CON1bits.T0CKPS = 0; //Prescaler 1:1
   T0CON1bits.T0ASYNC = 1; //Async mode - Must be set - bug from errata
   TMR0H = 0x20; //Preload 20 into TMR0H counter to make 1mS
   TMR0L = 0x00;
   PIR0bits.TMR0IF = 0; //Clear Interrupt flag
   T0CON0bits.T0EN = 1; //Enable timer 0
}

void PIN_Init(void)
{
    //LATx registers
    LATA = 0x00;
    LATB = 0x00;
    LATC = 0x00;

    //TRISx registers
    TRISA = 0xFF; //PORTA as inputs
    TRISB = 0x00;
    TRISC = 0x00;
  
    //ANSELx registers
    ANSELA = 0b00000001; //RA0 analog input
    ANSELB = 0x00;
    ANSELC = 0x00;
    
    //WPUx registers
    WPUA = 0b11111100;
    WPUB = 0x00;
    WPUC = 0x00;
    WPUE = 0x00;

    //ODx registers
    ODCONA = 0x00;
    ODCONB = 0x00;
    ODCONC = 0x00;

    CM1CON0bits.C1EN = 0; //Disable Comparator 1
    CM2CON0bits.C2EN = 0; //Disable Comparator 2
    INTCONbits.GIE =1; //Enable global interrupts
    INTCONbits.GIEH =1;
    INTCONbits.GIEL =1;
    INTCONbits.PEIE = 1; //Enable peripheral interrupts
    INTCONbits.IPEN = 0; //Disable interrupt priority
    PIE0bits.IOCIE = 1; //Enable Interrupt On Change interrupts
    
    PPSLOCK = 0x55;
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 0x00; // unlock PPS

    //IOCx registers

    // interrupt on change for group IOCxF - flag

    IOCAFbits.IOCAF0 = 0;
    IOCAFbits.IOCAF1 = 1;
    IOCAFbits.IOCAF2 = 0;
    IOCAFbits.IOCAF3 = 0;
    IOCAFbits.IOCAF4 = 0;
    IOCAFbits.IOCAF5 = 1;
    IOCAFbits.IOCAF6 = 0;
    IOCAFbits.IOCAF7 = 0;
   /*
    IOCBFbits.IOCBF0 = 0;
    IOCBFbits.IOCBF1 = 0;
    IOCBFbits.IOCBF2 = 0;
    IOCBFbits.IOCBF3 = 0;
    IOCCFbits.IOCCF0 = 0;
    IOCCFbits.IOCCF1 = 0;

    // interrupt on change for group IOCxN - negative
 */
    IOCANbits.IOCAN0 = 0; //Disable IOC negative detection on RA0 for pressure sensor
    IOCANbits.IOCAN1 = 1; //Enable IOC negative detection on RA1 for flow sensor
    IOCANbits.IOCAN2 = 1; //Enable IOC negative detection on RA2 for Ext in
    IOCANbits.IOCAN3 = 1; //Enable IOC negative detection on RA3 for Left button
    IOCANbits.IOCAN4 = 1; //Enable IOC negative detection on RA4 for Down button
    IOCANbits.IOCAN5 = 1; //Enable IOC negative detection on RA5 for Enter button
    IOCANbits.IOCAN6 = 1; //Enable IOC negative detection on RA6 for Right button
    IOCANbits.IOCAN7 = 1; //Enable IOC negative detection on RA7 for Up button

    
    IOCBNbits.IOCBN0 = 0;
    IOCBNbits.IOCBN1 = 0;
    IOCBNbits.IOCBN2 = 0;
    IOCBNbits.IOCBN3 = 0;
    IOCCNbits.IOCCN0 = 0;
    IOCCNbits.IOCCN1 = 0;

    // interrupt on change for group IOCCP - positive
    IOCAP = 0;
    //IOCAPbits.IOCAP1 = 1; //Enable IOC positive detection on RA1 for flow sensor
    IOCBPbits.IOCBP0 = 0;
    IOCBPbits.IOCBP1 = 0;
    IOCBPbits.IOCBP2 = 0;
    IOCBPbits.IOCBP3 = 0;
    IOCCPbits.IOCCP0 = 0;
    IOCCPbits.IOCCP1 = 0;

    PPSLOCK = 0x55;
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 0x01; // lock PPS
}

void ADC_Init(void)
{
    //10 bit resolution, result in ADCRESH and ADRESL, Right justified.
    ADON = 0; //Ensure ADC is off
    ADCON0bits.ADFM = 1; //Right justify result into ADRESH and ADRESL
    ADCON0bits.ADCS = 1; //Select FRC Clock
    ADPCH = 0x00; //RA0 is Analog channel
    ADCON0bits.ADON = 1; //Turn ADC On
}

void interrupt ISR(void)

{
    unsigned char tmrintpulse;
    
    if (PIR0bits.IOCIF) //Interrupt on change detected
    {
        if (IOCAFbits.IOCAF1) //IOC flag for RA1 detected
        {
              IOCAFbits.IOCAF1 = 0; //Reset IOC RA1 flag - should reset IOCIF
        }
        if (IOCAFbits.IOCAF5)
        {
              IOCAFbits.IOCAF5 = 0;
        }
            
    }
    
    if (PIR0bits.TMR0IF == 1) //Timer0 rollover detected
        {
            Milliseconds++; //Increment Milliseconds
            if (Milliseconds >= 500) //Indicate half second intervals
                {
                    SampleTime = 1; //Time to do stuff
                    secondspulse++; //Increment counter to work u second has elapsed
                    Milliseconds = 0;
                }
       
            if (secondspulse >=2) //Second pulse for flow counter
                {
                    Second = 1; //1 Second has elapsed
                    secondspulse = 0; //Reset Second counter
                    MinuteCounter++;
                }
                

                Second = 0; //Reset second counter
                
            if (MinuteCounter >=60) //1 minute interval

                {
                    Minutes++; //Increment minute counter
                    MinuteCounter = 0; //Reset minute counter
                }
            
            PIR0bits.TMR0IF = 0; //Clear Timer0 interrupt flag
        }
}


void main(void)
{
    
    PLL_Init(); //Configure the oscillator for the device
    TIMER_Init(); //Configure timers
    PIN_Init(); //Initialize I/O and Peripherals
    //ADC_Init(); //Setup ADC
    LCD_Init(); //Setup display
    LCD_cmd(CLRSCR); //Clear the LCD
    LCD_cmd(0x85); //Set cursor line 1 position 6
    LCD_cmd(0x0C); //Turn off cursor and blink
    LCD_string("Ready");
    __delay_ms(2000);
    LCD_cmd(CLRSCR);
    
 // WriteEEprom (0x0F, 0x0A);//test write to EEPROM
    
    Byte_read();

    Relay = 1;//For testing
    
    ROMData = NVMDAT;
    
    
    LCD_cmd(CLRSCR); //Clear the LCD
    LCD_cmd(0x85); //Set cursor line 1 position 6
    LCD_cmd(0x0C); //Turn off cursor and blink
    LCD_string("Ready2");
    __delay_ms(3000);
    
    
   char DisBuffer1[20];
    sprintf (DisBuffer1, "ROMData %u", ROMData);
    LCD_cmd(0xC0); //Line 2 position 1
    LCD_cmd(0x0C); //Turn off cursor and blink
    LCD_string(DisBuffer1);
         
    
    while(1)

    {
            
    }


}

/*
void WriteEEprom(unsigned int ROMAddress, unsigned char ROMData)
{
    // wait until all previous writes are completed (eeprom, flash and config-registers)
    while (NVMCON1bits.WR);

    // Disable Interrupts
    INTCONbits.GIE = 0;
    
    // Enable write operation
    NVMCON1bits.WREN = 1;
    
    // Define address to write
    NVMADR = (unsigned char)(ROMAddress >> 8);
    NVMADRL = ROMAddress;

    // sets data value to write
    NVMDAT = ROMData;

    // Unlock sequence
    NVMCON2 = 0x55;
    NVMCON2 = 0xAA;

    
    
    // This begins the write
    NVMCON1bits.WR = 1;

    // Disable Writes
    NVMCON1bits.WREN = 0;

    // Re-enable interrupts
    INTCONbits.GIE = 1;
}
*/


void Byte_read(void)
{

 NVMCON1bits.NVMREG = 0;
 NVMADR = 01;
 NVMCON1bits.RD = 1;
 
 while(NVMCON1bits.RD == 1);
 
}

 
lcd.c:
 
/*
 * File: lcd.c
 * Author:
 *
 * Created on 8 November 2018, 2:49 PM
 */


#include <xc.h>
#include "lcd.h"
#define _XTAL_FREQ 64000000 //Define 64Mb used for __delay_()

/****************** PIN Mapping *******************/
#define RS LATCbits.LATC5
#define RW LATCbits.LATC6
#define EN LATCbits.LATC7
#define BF PORTBbits.RB7
#define DATAPORT LATB

/************** Line Addr Mapping ******************/
#define LCD_LINE1 0x80
#define LCD_LINE2 0xC0

#define CLRSCR 0x01
#define DISPLAY_ON 0x0C
#define DISPLAY_OFF 0x08
#define DISPLAY_HOME 0x02
#define CURSOR_ON 0x0A
#define CURSOR_OFF 0x08
#define CURSOR_INC 0x06


void LCD_Init(void)
{
    __delay_ms(45);
    LCD_cmd(0x30); //Initialise
    LCD_cmd(0x30); //Initialise
    LCD_cmd(0x30); //Initialise
    LCD_cmd(0x38); // 2 Line, 5x7 display, 8 bit
    LCD_cmd(0x06); //Set mode to increment the address by one and to shift the cursor to the right, at the time of write
    LCD_cmd(0x0F); //Turn on display and flash cursor 00001D(display on/off)C(cursor on/off)B(Blink on/off)
    LCD_cmd(0x01); // Clear display
}

void LCD_data(unsigned char data)
{
    LCD_isbusy(); //Check that LCD has finished doing stuff
    RS = 1;
    RW = 0;
    EN = 1; //Assert LCD select
    DATAPORT = data; //Send display character data out Data lines
    __delay_us(50);
    EN = 0;
}

void LCD_cmd(unsigned char cmd)
{
    LCD_isbusy(); //Check that LCD has finished doing stuff
    RS = 0;
    RW = 0;
    EN = 1; //Assert LCD select
    DATAPORT = cmd; //Send display control data out Data lines
    __delay_us(50);
    EN = 0;
}

void LCD_isbusy(void)
{
    TRISBbits.TRISB7=1; // Make B7 an input
    RS = 0;
    RW = 1;
    EN = 1;
    __delay_us(50);
    while(BF);
    EN = 0;
    TRISBbits.TRISB7=0; // B7 back to Output
}

void LCD_string(char *buffer)
{
    while(*buffer) // Write data to LCD up to null
        {
            LCD_data(*buffer); // Write character to LCD
            buffer++; // Increment buffer
        }
}

#1

56 Replies Related Threads

    qhb
    Superb Member
    • Total Posts : 9224
    • Reward points : 0
    • Joined: 2016/06/05 14:55:32
    • Location: One step ahead...
    • Status: offline
    Re: EEPROM read routine interferes with LCD write 2018/12/25 22:24:26 (permalink)
    +2 (2)
    Add this line from your eeprom wr routine to also be at the start of your Byte_read() routine.
        // wait until all previous writes are completed (eeprom, flash and config-registers)
        while (NVMCON1bits.WR);

    As it is, you are trying to start the read before the previous write has finished.
     
    #2
    davekw7x
    Entropy++
    • Total Posts : 1664
    • Reward points : 0
    • Joined: 2012/01/16 12:01:07
    • Location: Left Coast, USA
    • Status: offline
    Re: EEPROM read routine interferes with LCD write 2018/12/25 22:28:40 (permalink)
    +3 (3)
    In order to access EEPROM, your program must set the upper two bits of NVMCON1, NVMCON1bits.NVMREG, to 0b00.  Your Byte_read() function does this.
     
    For consistent operation, when you leave any EEPROM access routine, you should restore the upper two bits to their previous value (probably 0b10, but I always save upon entry, and I restore the saved value before returning).  Your Byte_read() function does not do this.
     
    Regards,

    Dave
    post edited by davekw7x - 2018/12/25 22:46:47

    Sometimes I just can't help myself...
    #3
    du00000001
    Just Some Member
    • Total Posts : 2500
    • Reward points : 0
    • Joined: 2016/05/03 13:52:42
    • Location: Germany
    • Status: online
    Re: EEPROM read routine interferes with LCD write 2018/12/25 22:34:58 (permalink)
    +1 (1)
    What about following the flow diagram in the data sheet (DS40001816F-page 174) ?
    Instead of "inventing" your own code that might get stuck where waiting for NVM1CON.RD to become 0 ?
    (This might simply not happen.)
    "read operation completed" might well comprise the reading of NVMDAT - something not taking place in your current code. The data sheet clearly states that the EEPROM data is available in the next cycle following setting ...RD to 1. So there is no need to poll ...RD for returning to 0.

    PEBKAC / EBKAC / POBCAK / PICNIC (eventually see en.wikipedia.org)
    #4
    qhb
    Superb Member
    • Total Posts : 9224
    • Reward points : 0
    • Joined: 2016/06/05 14:55:32
    • Location: One step ahead...
    • Status: offline
    Re: EEPROM read routine interferes with LCD write 2018/12/25 22:38:27 (permalink)
    +1 (1)
    Ahhh, I missed that this was a K40.
    As Dave says, you need to take great care with NVMCON1 on those devices.
    What I mentioned still needs to be done, but is not causing your observed problem.
     
    post edited by qhb - 2018/12/25 23:41:32
    #5
    Trackhappy
    Starting Member
    • Total Posts : 51
    • Reward points : 0
    • Joined: 2016/11/03 16:07:08
    • Location: 0
    • Status: offline
    Re: EEPROM read routine interferes with LCD write 2018/12/25 23:36:10 (permalink)
    0
    Thanks speechless...  I have added that although in the test code I am not writing anything, the values are pre-burned into EEPROM. Added that line but no change.
     
    Dave, I will investigate and try that. Thanks.
     
    du.. Thanks. I added that in, trying to fix the problem, but will remove it as you suggest, although the data sheet says that it sets that back once the read is complete so it should in theory be a good indicator of completion I would have thought.
     
    Debug is a nuisance as with the lcd code in there I have to skip a bazillion times to get to the main code and each __delay_us() takes a few seconds to go through. Somebody experienced probably knows how to get around that.
     
    Without the lcd stuff, in debug mode it reads correctly. A byte read seems to stop the lcd code from working properly, which has me stumped.
     
     
    #6
    qhb
    Superb Member
    • Total Posts : 9224
    • Reward points : 0
    • Joined: 2016/06/05 14:55:32
    • Location: One step ahead...
    • Status: offline
    Re: EEPROM read routine interferes with LCD write 2018/12/25 23:43:27 (permalink)
    +1 (1)
    Are you sure you have put NVMCON1 back how it was?
    This is vital for any table reads in the C code (such as for constant strings) to keep working.
    #7
    Trackhappy
    Starting Member
    • Total Posts : 51
    • Reward points : 0
    • Joined: 2016/11/03 16:07:08
    • Location: 0
    • Status: offline
    Re: EEPROM read routine interferes with LCD write 2018/12/25 23:45:48 (permalink)
    +1 (1)
    Dave, You ROCK!
     
    Restoring those bits indeed made it carry on. I get the wrong value in the lcd display, but that is one for me to continue with. 
     
    Thanks again.
    Glenn.
     
    #8
    Trackhappy
    Starting Member
    • Total Posts : 51
    • Reward points : 0
    • Joined: 2016/11/03 16:07:08
    • Location: 0
    • Status: offline
    Re: EEPROM read routine interferes with LCD write - Solved thanks Dave!!! 2018/12/25 23:47:40 (permalink)
    0
    Thanks Dave.
    #9
    Trackhappy
    Starting Member
    • Total Posts : 51
    • Reward points : 0
    • Joined: 2016/11/03 16:07:08
    • Location: 0
    • Status: offline
    Re: EEPROM read routine interferes with LCD write - Solved thanks Dave!!! 2018/12/25 23:57:37 (permalink)
    0
    For reference, this is what I ended up with. :)
     
    void Byte_read(void)
    {
    // wait until all previous writes are completed (eeprom, flash and config-registers)
     while (NVMCON1bits.WR);
     
     unsigned char regorival = NVMCON1bits.NVMREG; //save NVMREG values
     
     NVMCON1bits.NVMREG = 0;
     NVMADR = 00;
     NVMCON1bits.RD = 1;
     NVMCON1bits.NVMREG = regorival;// Set them back
     
    }

    #10
    AMPS
    Super Member
    • Total Posts : 347
    • Reward points : 0
    • Status: offline
    Re: EEPROM read routine interferes with LCD write - Solved thanks Dave!!! 2018/12/26 00:22:26 (permalink)
    +1 (1)
    One doubt i am having in your code. how you identifying memory location to read EEPROM data.
    I have used MCC generated EEProm with PIC18F24K40 and its working well for reading internal EEPROM. you can also try below syntax and try the same
     

     
    void DATAEE_WriteByte(uint8_t bAdd, uint8_t bData)
    {
    uint8_t GIEBitValue = INTCONbits.GIE; // Save interrupt enable

    NVMADRL = (bAdd & 0xFF);
    NVMDAT = bData;
    NVMCON1bits.NVMREG = 0;
    NVMCON1bits.WREN = 1;
    INTCONbits.GIE = 0; // Disable interrupts
    NVMCON2 = 0x55;
    NVMCON2 = 0xAA;
    NVMCON1bits.WR = 1;
    // Wait for write to complete
    while (NVMCON1bits.WR)
    {
    }
    NVMCON1bits.WREN = 0;
    INTCONbits.GIE = GIEBitValue; // Restore interrupt enable
    }
    uint8_t DATAEE_ReadByte(uint8_t bAdd)
    {
    NVMADRL = (bAdd & 0xFF);
    NVMCON1bits.NVMREG = 0;
    NVMCON1bits.RD = 1;
    NOP(); // NOPs may be required for latency at high frequencies
    NOP();
    return (NVMDAT);
    }


    Amps
    *.*.*.*.*.*.*.*.*.*.*.*.*
    #11
    qhb
    Superb Member
    • Total Posts : 9224
    • Reward points : 0
    • Joined: 2016/06/05 14:55:32
    • Location: One step ahead...
    • Status: offline
    Re: EEPROM read routine interferes with LCD write - Solved thanks Dave!!! 2018/12/26 00:26:58 (permalink)
    +1 (1)
    Trackhappy
    For reference, this is what I ended up with. :)

    Just saving the entire NVMCON1 register would take less code.
     
    void Byte_read(void)
    {
    // wait until all previous writes are completed (eeprom, flash and config-registers)
     while (NVMCON1bits.WR);
     
     unsigned char regorival = NVMCON1; //save NVMREG values

     NVMCON1bits.NVMREG = 0;
     NVMADR = 00;
     NVMCON1bits.RD = 1;
     NVMCON1 = regorival;// Set them back
    }

    #12
    Trackhappy
    Starting Member
    • Total Posts : 51
    • Reward points : 0
    • Joined: 2016/11/03 16:07:08
    • Location: 0
    • Status: offline
    Re: EEPROM read routine interferes with LCD write - Solved thanks Dave!!! 2018/12/26 01:26:18 (permalink)
    0
    Thanks AMPS. That was my next challenge, for the function to accept an address to return. I had something in there but when I had issues I stripped it out to get the initial issue sorted first.
    Then it is time to write values... ;)
     
    #13
    AMPS
    Super Member
    • Total Posts : 347
    • Reward points : 0
    • Status: offline
    Re: EEPROM read routine interferes with LCD write - Solved thanks Dave!!! 2018/12/26 01:27:52 (permalink)
    +1 (1)
    I have given read and write function into Internal EEPROM. you could try with these function and check its working.
     
     

    Amps
    *.*.*.*.*.*.*.*.*.*.*.*.*
    #14
    Trackhappy
    Starting Member
    • Total Posts : 51
    • Reward points : 0
    • Joined: 2016/11/03 16:07:08
    • Location: 0
    • Status: offline
    Re: EEPROM read routine interferes with LCD write - Solved thanks Dave!!! 2018/12/26 01:34:30 (permalink)
    0
    Thank you AMPS. Will do.
    #15
    1and0
    Access is Denied
    • Total Posts : 8740
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: EEPROM read routine interferes with LCD write - Solved thanks Dave!!! 2018/12/26 02:21:08 (permalink)
    0
    ajitnayak87
    I have given read and write function into Internal EEPROM. you could try with these function and check its working.

    Those MCC generated functions accept only an 8-bit address, while the EEPROM on this PIC device has 1024 bytes. Also, those functions do not take care of the NVMREG bits, which is the cause of the problem here. :(
     
    Edit: Also, the two NOP()'s after setting the RD bit are unnecessary according to the datasheet.
    post edited by 1and0 - 2018/12/26 02:25:12
    #16
    1and0
    Access is Denied
    • Total Posts : 8740
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: EEPROM read routine interferes with LCD write - Solved thanks Dave!!! 2018/12/26 02:46:50 (permalink)
    0
    @OP, since this is a K40 part, have you applied the NVMREG errata?  Search this forum.
    #17
    AMPS
    Super Member
    • Total Posts : 347
    • Reward points : 0
    • Status: offline
    Re: EEPROM read routine interferes with LCD write - Solved thanks Dave!!! 2018/12/26 03:37:03 (permalink)
    0
    This is sample code i am testing . I used simulator for debugging. With this sample example code i could able to read and write into internal EEPROM
    memory.c
    /**
      MEMORY Generated Driver File

      @Company
        Microchip Technology Inc.

      @File Name
        memory.c

      @Summary
        This is the generated driver implementation file for the MEMORY driver using PIC10 / PIC12 / PIC16 / PIC18 MCUs

      @Description
        This file provides implementations of driver APIs for MEMORY.
        Generation Information :
            Product Revision : PIC10 / PIC12 / PIC16 / PIC18 MCUs - 1.65.2
            Device : PIC18F26K40
            Driver Version : 2.01
        The generated drivers are tested against the following:
            Compiler : XC8 1.45
            MPLAB : MPLAB X 4.15
    */

    /*
        (c) 2018 Microchip Technology Inc. and its subsidiaries.
        
        Subject to your compliance with these terms, you may use Microchip software and any
        derivatives exclusively with Microchip products. It is your responsibility to comply with third party
        license terms applicable to your use of third party software (including open source software) that
        may accompany Microchip software.
        
        THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
        EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY
        IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS
        FOR A PARTICULAR PURPOSE.
        
        IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
        INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
        WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP
        HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO
        THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL
        CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT
        OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS
        SOFTWARE.
    */

    /**
      Section: Included Files
    */

    #include <xc.h>
    #include "memory.h"


    /**
      Section: Flash Module APIs
    */

    uint8_t FLASH_ReadByte(uint32_t flashAddr)
    {
     NVMCON1bits.NVMREG = 2;
        TBLPTRU = (uint8_t)((flashAddr & 0x00FF0000) >> 16);
        TBLPTRH = (uint8_t)((flashAddr & 0x0000FF00)>> 8);
        TBLPTRL = (uint8_t)(flashAddr & 0x000000FF);

        asm("TBLRD");

        return (TABLAT);
    }

    uint16_t FLASH_ReadWord(uint32_t flashAddr)
    {
        return ((((uint16_t)FLASH_ReadByte(flashAddr+1))<<8)|(FLASH_ReadByte(flashAddr)));
    }

    void FLASH_WriteByte(uint32_t flashAddr, uint8_t *flashRdBufPtr, uint8_t byte)
    {
        uint32_t blockStartAddr = (uint32_t)(flashAddr & ((END_FLASH-1) ^ (ERASE_FLASH_BLOCKSIZE-1)));
        uint8_t offset = (uint8_t)(flashAddr & (ERASE_FLASH_BLOCKSIZE-1));
        uint8_t i;

        // Entire row will be erased, read and save the existing data
        for (i=0; i<ERASE_FLASH_BLOCKSIZE; i++)
        {
            flashRdBufPtr[i] = FLASH_ReadByte((blockStartAddr+i));
        }

        // Load byte at offset
        flashRdBufPtr[offset] = byte;

        // Writes buffer contents to current block
        FLASH_WriteBlock(blockStartAddr, flashRdBufPtr);
    }

    int8_t FLASH_WriteBlock(uint32_t writeAddr, uint8_t *flashWrBufPtr)
    {
        uint32_t blockStartAddr = (uint32_t )(writeAddr & ((END_FLASH-1) ^ (ERASE_FLASH_BLOCKSIZE-1)));
     uint8_t GIEBitValue = INTCONbits.GIE; // Save interrupt enable
        uint8_t i;

        // Flash write must start at the beginning of a row
        if( writeAddr != blockStartAddr )
        {
            return -1;
        }

        // Block erase sequence
        FLASH_EraseBlock(writeAddr);

        // Block write sequence
        TBLPTRU = (uint8_t)((writeAddr & 0x00FF0000) >> 16); // Load Table point register
        TBLPTRH = (uint8_t)((writeAddr & 0x0000FF00)>> 8);
        TBLPTRL = (uint8_t)(writeAddr & 0x000000FF);

        // Write block of data
        for (i=0; i<WRITE_FLASH_BLOCKSIZE; i++)
        {
            TABLAT = flashWrBufPtr[i]; // Load data byte

            if (i == (WRITE_FLASH_BLOCKSIZE-1))
            {
                asm("TBLWT");
            }
            else
            {
                asm("TBLWTPOSTINC");
            }
        }

        NVMCON1bits.NVMREG = 2;
        NVMCON1bits.WREN = 1;
     INTCONbits.GIE = 0; // Disable interrupts
        NVMCON2 = 0x55;
        NVMCON2 = 0xAA;
        NVMCON1bits.WR = 1; // Start program

        NVMCON1bits.WREN = 0; // Disable writes to memory
     INTCONbits.GIE = GIEBitValue; // Restore interrupt enable
        
        return 0;
    }

    void FLASH_EraseBlock(uint32_t baseAddr)
    {
     uint8_t GIEBitValue = INTCONbits.GIE; // Save interrupt enable
     
        TBLPTRU = (uint8_t)((baseAddr & 0x00FF0000) >> 16);
        TBLPTRH = (uint8_t)((baseAddr & 0x0000FF00)>> 8);
        TBLPTRL = (uint8_t)(baseAddr & 0x000000FF);

        NVMCON1bits.NVMREG = 2;
        NVMCON1bits.WREN = 1;
        NVMCON1bits.FREE = 1;
     INTCONbits.GIE = 0; // Disable interrupts
     NVMCON2 = 0x55;
        NVMCON2 = 0xAA;
        NVMCON1bits.WR = 1;
     INTCONbits.GIE = GIEBitValue; // Restore interrupt enable
    }

    /**
      Section: Data EEPROM Module APIs
    */

    void DATAEE_WriteByte(uint16_t bAdd, uint8_t bData)
    {
     uint8_t GIEBitValue = INTCONbits.GIE; // Save interrupt enable

        NVMADRH = ((bAdd >> 8) & 0x03);
        NVMADRL = (bAdd & 0xFF);
        NVMDAT = bData;
        NVMCON1bits.NVMREG = 0;
        NVMCON1bits.WREN = 1;
     INTCONbits.GIE = 0; // Disable interrupts
        NVMCON2 = 0x55;
        NVMCON2 = 0xAA;
        NVMCON1bits.WR = 1;
        // Wait for write to complete
        while (NVMCON1bits.WR)
        {
        }

        NVMCON1bits.WREN = 0;
     INTCONbits.GIE = GIEBitValue; // Restore interrupt enable
    }

    uint8_t DATAEE_ReadByte(uint16_t bAdd)
    {
        NVMADRH = ((bAdd >> 8) & 0x03);
        NVMADRL = (bAdd & 0xFF);
        NVMCON1bits.NVMREG = 0;
        NVMCON1bits.RD = 1;
        NOP(); // NOPs may be required for latency at high frequencies
        NOP();

        return (NVMDAT);
    }

    void MEMORY_Tasks( void )
    {
        /* TODO : Add interrupt handling code */
        PIR7bits.NVMIF = 0;
    }
    /**
     End of File
    */

     
     
    main.c
     

    #include "mcc_generated_files/mcc.h"

    /*
                             Main application
     */
    void main(void)
    {
        // Initialize the device
        SYSTEM_Initialize();

        // If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
        // If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global and Peripheral Interrupts
        // Use the following macros to:

        // Enable the Global Interrupts
        //INTERRUPT_GlobalInterruptEnable();

        // Disable the Global Interrupts
        //INTERRUPT_GlobalInterruptDisable();

        // Enable the Peripheral Interrupts
        //INTERRUPT_PeripheralInterruptEnable();

        // Disable the Peripheral Interrupts
        //INTERRUPT_PeripheralInterruptDisable();

          DATAEE_WriteByte(0X01,0X0A);
          DATAEE_WriteByte(0X02,0X11);
         DATAEE_WriteByte(0X03,0X12);
        while (1)
        {
            
            DATAEE_ReadByte(0X01);
             DATAEE_ReadByte(0X02);
              DATAEE_ReadByte(0X03);
              
        }
    }

    Attached Image(s)


    Amps
    *.*.*.*.*.*.*.*.*.*.*.*.*
    #18
    1and0
    Access is Denied
    • Total Posts : 8740
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: EEPROM read routine interferes with LCD write - Solved thanks Dave!!! 2018/12/26 04:44:21 (permalink)
    0
    ajitnayak87
    This is sample code i am testing . I used simulator for debugging. With this sample example code i could able to read and write into internal EEPROM

    Try simulating this
      while (1)
      {
        uint8_t foo;
        foo = DATAEE_ReadByte(0X01);
        printf("Address 0x01 = %u", foo);

        foo = DATAEE_ReadByte(0X02);
        printf("Address 0x02 = %u", foo);

        foo = DATAEE_ReadByte(0X03);
        printf("Address 0x03 = %u", foo);
      }

     
    Edit: It's better to test with real hardware.
    post edited by 1and0 - 2018/12/26 10:53:26
    #19
    davekw7x
    Entropy++
    • Total Posts : 1664
    • Reward points : 0
    • Joined: 2012/01/16 12:01:07
    • Location: Left Coast, USA
    • Status: offline
    Re: EEPROM read routine interferes with LCD write - Solved thanks Dave!!! 2018/12/26 10:11:10 (permalink)
    +1 (1)
    1and0
    @OP, since this is a K40 part, have you applied the NVMREG errata?  Search this forum.



    Oh, man...I have been trying to cut down on forum bandwidth : my suggestion, with no explanation, was based on my experience with "original rev" parts  (27K40 rev 2 and 47K40 rev 2).  If you don't do the NVMREG thing you will never get satisfaction from statements that use string literals like LCD_string("Ready2");
     
    But---sometimes I just can't help myself---I find myself compelled to supply a little more information.
     
    Now, even if you do the NVMREG thing with these early rev chips, you still have to save and restore NVMREG bits when you change them.
     
    With later rev chips, such as 47K40 rev A3, not only do you not have to do the NVMREG startup thing, it also happens that, unlike previous revisions, these devices comply with the current data sheet statement that
    Section 11 of DS40001844E
    The NVMREG bits are don't cares for read access.

     
    That's the real problem that wasn't exactly spelled out in the errata: In early rev chips, NVMREG bit values affect read operations as well as write operations.
     
    Now MCC-generated files don't take this into account (at least they didn't have this the last time I looked).  Furthermore, the simulator, if it works for a particular module, will always try to simulate the device's description in the data sheet, and won't have results that depend on chip bugs that differ from the documentation.
     
    That's the reason I rarely post suggestions that I haven't been able to test on real hardware.  Reading data sheets doesn't always tell the tale.  Also, I would rather spend time debugging my hardware/software than debugging the simulator. 
     
    Bottom line: With my PIC47K40 rev A3, it is not necessary to have the NVMREG fix in the startup code and it is not necessary to save and restore the NVMREG bits when reading from EEPROM.  (See Footnote.)
     
    For a commercial product, since you can not, in general, get a guarantee as to which rev chip will come through your supply chain, I would appy the NVMREG startup fix and I would save and restore NVMREG when accessing EEPROM.
     
    Regards,

    Dave
     
    Footnote:
    Note that errata for 27K40/47K40 is different from other chips in the family as to which revs are affected.
    post edited by davekw7x - 2018/12/26 10:24:40

    Sometimes I just can't help myself...
    #20
    Page: 123 > Showing page 1 of 3
    Jump to:
    © 2019 APG vNext Commercial Version 4.5