This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

In-Application on Chip Flash Programming

Hi,
I use the flash routines from the file download area
"XC16x In-Application On-Chip Flash-Programming".
This example is for a 20 Mhz CPU clock. My XC164CM- board runs with 40 Mhz. The flash routines doesnt work at 40 Mhz. At my opinion is it enough to change PLLCON from 0x7884 to 0x7889 for 20 Mhz. (UnlockProtReg is also used). My problem is: The first printf-instruction after switch back to 40 Mhz is wrong. The first one or two charcters are not correct. This is undependent from interrupts. Could this be a stack-problem? But the progam is so small. The second problem is thats a little bit more than 64 bytes are written at the flash memory.
Has someone expiriences ?
Kindly regards
Rainer
srom.c :

#include <string.h>
#include <intrins.h>
#include <srom.h>             // SROM Handling definitions
#include <XC167.h>
#include <stdio.h>

SROM_PS (PFLASH)              // define SROM program segment from PFLASH.A66

#define FLASH_ADR 0xC1F000L       // Address in on-chip flash, that is used to write to

extern void far  SerComm_Init (void);

extern void far UnlockProtecReg(void);

// Write 64 Bytes to target_adr in Flash Memory
extern int  far PFlash_Write (void huge *target_adr, void huge *buffer);

// Erase the Flash memory sector specified by sector_adr
extern int  far PFlash_Erase (void huge *sector_adr);

unsigned char buf[64] = "This is a string that is written to on-chip flash 22.09.2007";

void main (void)  {
  unsigned char huge *pFLASH_ROM = FLASH_ADR;
  unsigned char i,x_ch;
  unsigned long int a = (SROM_PS_TRG(PFLASH));
  unsigned long int b = (SROM_PS_SRC(PFLASH));
  unsigned long int c = (SROM_PS_LEN(PFLASH));
  unsigned short Revision    = 0x0;
  unsigned int   myPLLCON_20 = 0x7889;
  unsigned int   myPLLCON_40 = 0x7884;

  SerComm_Init();

  printf("\n\n0x%.8LX:\n",(unsigned long)pFLASH_ROM);

  for (i=0;i<64;i++)
        {
         printf("%c",*pFLASH_ROM);
         pFLASH_ROM++;
        }
  printf("\n");

  _bfld_ (PSW, 0xF000, 0xF000); // disable interrupts
  UnlockProtecReg();
  PLLCON = myPLLCON_20;
  _bfld_ (PSW, 0xF000, 0x0000); // enable interrupts

  // copy flash program code to execution address
  hmemcpy (SROM_PS_TRG(PFLASH), SROM_PS_SRC(PFLASH), SROM_PS_LEN(PFLASH));

  _bfld_ (PSW, 0xF000, 0xF000); // disable interrupts
  PFlash_Erase (FLASH_ADR);     // Erase sector
  _bfld_ (PSW, 0xF000, 0x0000); // enable interrupts

  _nop_();

  _bfld_ (PSW, 0xF000, 0xF000); // disable interrupts
  PFlash_Write (FLASH_ADR, buf);// program 64 bytes
  _bfld_ (PSW, 0xF000, 0x0000); // enable interrupts

  _bfld_ (PSW, 0xF000, 0xF000); // disable interrupts
  UnlockProtecReg();
  PLLCON = myPLLCON_40;
  _bfld_ (PSW, 0xF000, 0x0000); // enable interrupts

  Revision = IDCHIP & 0x00FF;   // Read Chip Revision

  printf("Hello, back to 40 Mhz!\n");
  printf("Revision: %.4X\n",Revision);
  printf("\nPress key .............");
  x_ch = _getkey();  printf("\n");
  pFLASH_ROM = FLASH_ADR;
  for (i=0;i<64;i++)
        {
         printf("0x%.8LX: %c(%u)\n",(unsigned long)pFLASH_ROM,*pFLASH_ROM,*pFLASH_ROM);
         pFLASH_ROM++;
        }

  _nop_();

  printf("...ready!\n");
  while (1);

Parents
  • Maybe the reason for the faulty behaviour could be the 8 stage transmit FIFO that can be used by the serial interface.

    Are all 64 chars plus newline displayed correctly before switching to 20MHz? If not, some data may be removed from the FIFO after switching to 20MHz, probably resulting in wrong bit timings and garbled chars.

    I'm only guessing as I do not know how your serial interface is set up and what UnlockProtecReg() is doing exactly.

Reply
  • Maybe the reason for the faulty behaviour could be the 8 stage transmit FIFO that can be used by the serial interface.

    Are all 64 chars plus newline displayed correctly before switching to 20MHz? If not, some data may be removed from the FIFO after switching to 20MHz, probably resulting in wrong bit timings and garbled chars.

    I'm only guessing as I do not know how your serial interface is set up and what UnlockProtecReg() is doing exactly.

Children
  • Hi Thomas,

    wow FIFO - okay I will be tested !
    Before I switch to 20 Mhz are all characters okay.
    UnlockProtReg is necessary before you can write to the
    PLLCON-register, because this register has a security mechanism.
    Rainer

    UnlockProtecReg.c :

    #include <xc16x.h>
    
    void UnlockProtecReg(void)
    {
      unsigned int uwPASSWORD;
      if((SCUSLS & 0x1800) == 0x0800)      // if low protected mode
      {
        uwPASSWORD = SCUSLS & 0x00FF;
        uwPASSWORD = (~uwPASSWORD) & 0x00FF;
        SCUSLC = 0x8E00 | uwPASSWORD;      // command 4
      }  // end if low protected mode
      if((SCUSLS & 0x1800) == 0x1800)      // if write protected mode
      {
        SCUSLC = 0xAAAA;                   // command 0
        SCUSLC = 0x5554;                   // command 1
        uwPASSWORD = SCUSLS & 0x00FF;
        uwPASSWORD = (~uwPASSWORD) & 0x00FF;
        SCUSLC = 0x9600 | uwPASSWORD;      // command 2
        SCUSLC = 0x0800;                   // command 3; new PASSWORD is 0x00
        uwPASSWORD = SCUSLS & 0x00FF;
        uwPASSWORD = (~uwPASSWORD) & 0x00FF;
        SCUSLC = 0x8E00 | uwPASSWORD;      // command 4
      }  // end if write protected mode
    }
    

    and SerComm.c :

    #include <xc16x.h>
    
    // @ 40 Mhz
    
    void SerComm_Init()
            {
             // SET PORT 3.10 OUTPUT LATCH (TXD)
             P3            |= 0x0400;
             // SET PORT 3.10 DIRECTION CONTROL (TXD OUTPUT)
             DP3           |= 0x0400;
             // RESET PORT P3.11 DIRECTION CONTROL (RXD INPUT)
             DP3           &= 0xF7FF;
             // SET TRANSMIT INTERRUPT FLAG
             ASC0_TIC       =   0x80;
             // DELETE RECEIVE INTERRUPT FLAG
             ASC0_RIC       =   0x00;
             // BAUDRATE 19200 (0x40), 38400 (0x20), 57600 (0x14), 76800(0x10), 115200 (0x0A)
             ASC0_BG        =   0x0A;
             // SET SERIAL MODE
             ASC0_CON       = 0x8011;
             // Alternate I/O Source Port 3 Selection
             // P3.11 ASC0 RxD, P3.10 ASC0 TxD
             ALTSEL0P3     |= 0x0C00;
            }
    

  • When changing a PLL, the frequency change is not instant. Doesn't the processor have a flag you can check to know when the PLL has locked at the new frequency?

    If it doesn't, then you must manually add a delay before starting to use the serial port. If the baudrate generator gets its frequency after the PLL, the baudrate will be very wrong until the PLL is locked.

  • Hi,
    I tested a delay with some microseconds and the effect was indifferent. Characters are lost or wrong.
    A reinitialisation of the serial port has no effect.

    Kindly regards
    Rainer

  • You are running 115200 baud. Count number of broken characters times number of bits/character and you get an indication about how long it takes until the frequency is reasonably correct. Each character takes about 0.1ms so you probably didn't delay long enough before starting to use the serial port.

    Note that all other PLL-dependant functions (timers, PWM, ...) also gets affected. Have you checked in the datasheet if there is a flag available to check when the PLL is locked?

  • I found the register SYSSTAT at the manual with the bit PLLLOCK ... okay, thanks for the suggestion.
    I try it.

    Kindly regards
    Rainer

  • Hi,
    :-(( no results with while loops:

    while (PLLLOCK != 0xC804);
    

    or

    while (ASC0_FSTAT != 0x0000) ;
    


    the first two characters persists wrong.

    emmmhhh
    Rainer

  • Sorry,

    while (SYSSTAT != 0xC804) ;
    


    is correct

    Rainer