From b229f47321eda1f1a1ac200fdc6501129bcf6378 Mon Sep 17 00:00:00 2001 From: Mircea Neacsu Date: Thu, 25 Feb 2021 22:17:57 -0500 Subject: [PATCH 1/2] Added serial flash functions for RCM4200 --- Samples/Libraries/RCM42xx.LIB | 866 +++++++++++++++--- Samples/RCM4200/Serial_Flash/SFLASH_INSPECT.C | 528 +++++++---- 2 files changed, 1092 insertions(+), 302 deletions(-) diff --git a/Samples/Libraries/RCM42xx.LIB b/Samples/Libraries/RCM42xx.LIB index 9a06ff3..72b3ac9 100644 --- a/Samples/Libraries/RCM42xx.LIB +++ b/Samples/Libraries/RCM42xx.LIB @@ -1,6 +1,7 @@ /* - Copyright (c) 2015, Digi International Inc. - + Original work Copyright (c) 2015, Digi International Inc. + Copyright (c) 2021 Mircea Neacsu + Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. @@ -18,7 +19,13 @@ #define __RCM42XX_LIB #if !RCM4200_SERIES - #fatal "RCM42xx.LIB only supports RCM42xx series boards." + #fatal "RCM42xx.LIB only supports RCM42xx series boards." +#endif + +#ifndef RCM42XX_DEBUG +#define rcm42xx_debug __nodebug +#else +#define rcm42xx_debug __debug #endif /*** EndHeader */ @@ -26,93 +33,125 @@ /* START LIBRARY DESCRIPTION ********************************************* RCM42xx.LIB -DESCRIPTION: This is a sample library only. +DESCRIPTION: This is a sample library only. - Use with RCM42xx series controllers and prototyping boards. - Add or modify functions to suit your applications. + Use with RCM42xx series controllers and prototyping boards. + Add or modify functions to suit your applications. - RCM4200 Standard Setup: - 8-Bit Flash (512KB) - 8-Bit Fast SRAM (512KB) - 8-Bit SRAM (512KB) - 12-Bit, 8-Channel ADC (ADS7870) - 100BASE-T Ethernet (ASIX) + RCM4200 Standard Setup: + 8-Bit Flash (512KB) + 8-Bit Fast SRAM (512KB) + 8-Bit SRAM (512KB) + 12-Bit, 8-Channel ADC (ADS7870) + 100BASE-T Ethernet (ASIX) - RCM4210 Standard Setup: - 8-Bit Flash (512KB) - 8-Bit SRAM (512KB) - 100BASE-T Ethernet (ASIX) + RCM4210 Standard Setup: + 8-Bit Flash (512KB) + 8-Bit SRAM (512KB) + 100BASE-T Ethernet (ASIX) REVISION HISTORY: +20-Feb-2021 Mircea Neacsu - Added serial flash functions 20-Sep-2006 tbc Updated brdInit(), added check for ADC_ONBOARD. -06-Sep-2006 tbc Created RCM42XX.LIB from RCM40XX.LIB. +06-Sep-2006 tbc Created RCM42XX.LIB from RCM40XX.LIB. END DESCRIPTION **********************************************************/ /*** BeginHeader */ ////////// // required for A/D conversion operations -// make changes below to match your application +// make changes below to match your application ////////// -#define DEVELOPMENT_BOARD // Indicate development board LIB being used +//#define DEVELOPMENT_BOARD // Indicate development board LIB being used +#ifndef DISABLE_ADC #ifdef ADC_ONBOARD - - #use "ADC_ADS7870.LIB" + #use "ADC_ADS7870.LIB" +#endif +#else +#undef ADC_ONBOARD #endif -/*** EndHeader */ +// divisor for serial flash clock +#define SF_SPI_DIVISOR 0 //use directly pclck/2 (14.75 MHz) + +#define SF_CS_BIT 5 //serial flash CS bit (active high) +#define SF_TXE_BIT 3 //serial flash Tx Empty bit (on SCSR register) +#define SF_TXIDL_BIT 2 //serial flash Tx Idle bit (on SCSR register) +#define SF_RXRDY_BIT 7 //serial flash Rx ready bit (on SCSR register) +#define SF_RXRDY_MASK 0x80 //serial flash Rx ready mask (on SCSR register) + +#define SF_STATRDY_MASK 0x80 // ready bit in status register +#define SF_DEASSERT 0x100 //flag to change chip select (CS) signal + +/* + Descriptor for Adesto AT45DB641E serial flash chip: + pages = 32768 + pagebitshift = 9 + pagesize = 264 +*/ +extern struct SFDEV_STUCT { + long pages; + int pagebitshift; + int pagesize; +} sf_rcm4200; + -/*** BeginHeader __brdinitflag */ -extern int __brdinitflag; /*** EndHeader */ -int __brdinitflag; //Board init function flag -/*** BeginHeader brdInit */ +/*** BeginHeader brdInit, __brdinitflag, sf_rcm4200*/ void brdInit(); +extern int __brdinitflag; /*** EndHeader */ +int __brdinitflag; //Board init function flag +struct SFDEV_STUCT sf_rcm4200; //Info about on board serial flash /* START FUNCTION DESCRIPTION ******************************************** -brdInit +brdInit -SYNTAX: void brdInit (void); +SYNTAX: void brdInit (void); -DESCRIPTION: This function initializes parallel ports A through E for - RCM42xx series core modules running on an RCM42xx series - prototyping board. +DESCRIPTION: This function initializes parallel ports A through E for + RCM42xx series core modules running on an RCM42xx series + prototyping board. - Default I/O port configuration: - ------------------------------- - The brdInit function sets a default I/O configuration - based on the core module board type detected at compile - time. See the tables at the end of this function - description for complete details. + Default I/O port configuration: + ------------------------------- + The brdInit function sets a default I/O configuration + based on the core module board type detected at compile + time. See the tables at the end of this function + description for complete details. - Note: - ----- - This function is intended for demonstration purposes only - and can be modified for your applications. + Note: + ----- + This function is intended for demonstration purposes only + and can be modified for your applications. -PARAMETER: None +PARAMETER: None -RETURN VALUE: None +RETURN VALUE: None ------------------------------------------------------------------------------- General information and I/O initialization when using am RCM42xx series core module on an RCM42xx prototpying board ------------------------------------------------------------------------------- - Summary of initialization - ------------------------- - 1. I/O port pins are configured for protoboard operation. - 2. Unused configurable I/O are set to outputs. - 3. RS232 is not enabled. - 4. LED's are off. - 5. Slave port is disabled. + Summary of initialization + ------------------------- + 1. I/O port pins are configured for protoboard operation. + 2. Unused configurable I/O are set to outputs. + 3. RS232 is not enabled. + 4. LED's are off. + 5. Slave port is disabled. + 6. Serial flash on serial C: + PC2 - SDI + PC3 - SDO + PE7 - SCLK + TXDD+ - CS (active high) Pin Port Non-ADC Function I/O I/O State ==== ==== =========================== ====== ============================ @@ -163,7 +202,7 @@ Pin Port Non-ADC Function I/O I/O State 38 PE6 Not used Output High 39 PE7 Serial Flash SCLK Output High - The following only initializes on boards with ADC capability. +The following only initializes on boards with ADC capability. Pin Port ADC Function I/O I/O State ==== ==== =========================== ====== ============================ @@ -182,78 +221,683 @@ Pin Port ADC Function I/O I/O State END DESCRIPTION **********************************************************/ -__nodebug +rcm42xx_debug void brdInit() { - #GLOBAL_INIT {__brdinitflag = FALSE;} + #GLOBAL_INIT {__brdinitflag = FALSE;} - __brdinitflag = TRUE; + __brdinitflag = TRUE; - ///////////////////////////////////////////////////////////////////////// - // Configure Port A + ///////////////////////////////////////////////////////////////////////// + // Configure Port A ///////////////////////////////////////////////////////////////////////// - WrPortI(PADR, &PADRShadow, 0x00); //set to output all low - WrPortI(SPCR, &SPCRShadow, 0x84); //sets all bits to output + WrPortI(PADR, &PADRShadow, 0x00); //set to output all low + WrPortI(SPCR, &SPCRShadow, 0x84); //sets all bits to output + + ///////////////////////////////////////////////////////////////////////// + // Configure Port B + // This pin will be setup in anaInConfig() below if ADC_ONBOARD + // PB0 SCLK Output Serial clock + ///////////////////////////////////////////////////////////////////////// + WrPortI(PBDR, &PBDRShadow, 0xCF); + WrPortI(PBDDR, &PBDDRShadow, 0xCF); + + ///////////////////////////////////////////////////////////////////////// + // Configure Port C + // These two pins will be setup in anaInConfig() below if ADC_ONBOARD + // PC4 SDI Output Serial data to ADC chip + // PC5 SDO Input Serial data from ADC chip + ///////////////////////////////////////////////////////////////////////// + WrPortI(PCFR, &PCFRShadow, (PCFRShadow & 0xC5) | 0x04); + WrPortI(PCDCR, &PCDCRShadow, (PCDCRShadow & 0xC0)); + WrPortI(PCDR, &PCDRShadow, (PCDRShadow & 0xF5)); + WrPortI(PCDDR, &PCDDRShadow, (PCDDRShadow & 0xC0) | 0x35); + + ///////////////////////////////////////////////////////////////////////// + // Configure Port D + ///////////////////////////////////////////////////////////////////////// + WrPortI(PDCR, &PDCRShadow, 0x00); // clear all bits to pclk/2 + WrPortI(PDFR, &PDFRShadow, 0x00); // No special functions + WrPortI(PDDCR, &PDDCRShadow, 0x00); // clear all bits to drive high and low + WrPortI(PDDR, &PDDRShadow, 0xFF); // set all bits high + WrPortI(PDDDR, &PDDDRShadow, 0xFF); // set all bits to output + + ///////////////////////////////////////////////////////////////////////// + // Configure Port E + // This pin will be setup in anaInConfig() below if not polling the ADC + // PE0 BUSY Input Busy signal from ADC chip + // Ethernet driver will set up PE2, Serial Flash driver will set up PE7 + ///////////////////////////////////////////////////////////////////////// + WrPortI(PECR, &PECRShadow, 0x00); // clear all bits to pclk/2 + WrPortI(PEFR, &PEFRShadow, 0x80); // PE7 alternate function + WrPortI(PEAHR, &PEAHRShadow, 0xC0); // PE7 alt function = SCLKC + WrPortI(PEDCR, &PEDCRShadow, 0x00); // clear all bits to drive high and low + WrPortI(PEDR, &PEDRShadow, 0xFF); // set all bits high + WrPortI(PEDDR, &PEDDRShadow, 0xFF); // set all bits to output + + // Serial flash initialization + BitWrPortI(TACR, &TACRShadow, 0, 6); //use pclk/2 for TAT6R + WrPortI (TAT6R, &TAT6RShadow, SF_SPI_DIVISOR); + WrPortI (SCCR, &SCCRShadow, 0x0c); // Clocked serial mode with internal clock + WrPortI (SCER, &SCERShadow, 0x08); //SPI mode 0, MSB first + BitWrPortI(NAPCR, &NAPCRShadow, 0, SF_CS_BIT); //make sure serial flash is deselected + + //values for Adesto AT45DB641E + sf_rcm4200.pages = 32768; + sf_rcm4200.pagebitshift = 9; + sf_rcm4200.pagesize = 264; + + //--------------------------------------------------------------------- + // set global power save control self-timed chip select + //--------------------------------------------------------------------- +// WrPortI(GPSCR, &GPSCRShadow, GPSCRShadow|0xe0); //set to 109 nsec - ///////////////////////////////////////////////////////////////////////// - // Configure Port B - // This pin will be setup in anaInConfig() below if ADC_ONBOARD - // PB0 SCLK Output Serial clock - ///////////////////////////////////////////////////////////////////////// - WrPortI(PBDR, &PBDRShadow, 0xCF); - WrPortI(PBDDR, &PBDDRShadow, 0xCF); +#ifdef ADC_ONBOARD + // clear table and read all calibration constants + memset(_adcCalibS, 0, sizeof(_adcCalibS)); + memset(_adcCalibD, 0, sizeof(_adcCalibD)); + memset(_adcCalibM, 0, sizeof(_adcCalibM)); + anaInEERd(ALLCHAN, SINGLE, 0); + anaInEERd(ALLCHAN, DIFF, 0); + anaInEERd(ALLCHAN, mAMP, 0); + + // setup sclk + anaInConfig(0x18, 0x81, ADC_SCLKBRATE); //reset adc device and sclk byte rate +#endif +} - ///////////////////////////////////////////////////////////////////////// - // Configure Port C - // These two pins will be setup in anaInConfig() below if ADC_ONBOARD - // PC4 SDI Output Serial data to ADC chip - // PC5 SDO Input Serial data from ADC chip - ///////////////////////////////////////////////////////////////////////// - WrPortI(PCFR, &PCFRShadow, (PCFRShadow & 0xC5)); - WrPortI(PCDCR, &PCDCRShadow, (PCDCRShadow & 0xC0)); - WrPortI(PCDR, &PCDRShadow, (PCDRShadow & 0xF5)); - WrPortI(PCDDR, &PCDDRShadow, (PCDDRShadow & 0xC0) | 0x35); +/*** BeginHeader sf_wait_ready, af_rxbyte, sf_command */ +int sf_wait_ready (); +unsigned char sf_rxbyte (); +void sf_command (int opcode, long addr); - ///////////////////////////////////////////////////////////////////////// - // Configure Port D - ///////////////////////////////////////////////////////////////////////// - WrPortI(PDCR, &PDCRShadow, 0x00); // clear all bits to pclk/2 - WrPortI(PDFR, &PDFRShadow, 0x00); // No special functions - WrPortI(PDDCR, &PDDCRShadow, 0x00); // clear all bits to drive high and low - WrPortI(PDDR, &PDDRShadow, 0xFF); // set all bits high - WrPortI(PDDDR, &PDDDRShadow, 0xFF); // set all bits to output +/*** EndHeader */ +/* START FUNCTION DESCRIPTION ******************************************** +sf_rxbyte - ///////////////////////////////////////////////////////////////////////// - // Configure Port E - // This pin will be setup in anaInConfig() below if not polling the ADC - // PE0 BUSY Input Busy signal from ADC chip - // Ethernet driver will set up PE2, Serial Flash driver will set up PE7 - ///////////////////////////////////////////////////////////////////////// - WrPortI(PECR, &PECRShadow, 0x00); // clear all bits to pclk/2 - WrPortI(PEFR, &PEFRShadow, 0x00); // No special functions - WrPortI(PEDCR, &PEDCRShadow, 0x00); // clear all bits to drive high and low - WrPortI(PEDR, &PEDRShadow, 0xFF); // set all bits high - WrPortI(PEDDR, &PEDDRShadow, 0xFF); // set all bits to output + Read one byte from serial flash chip - //--------------------------------------------------------------------- - // set global power save control self-timed chip select - //--------------------------------------------------------------------- -// WrPortI(GPSCR, &GPSCRShadow, GPSCRShadow|0xe0); //set to 109 nsec + Syntax: unsigned char sf_rxbyte (); -#ifdef ADC_ONBOARD - // clear table and read all calibration constants - memset(_adcCalibS, 0, sizeof(_adcCalibS)); - memset(_adcCalibD, 0, sizeof(_adcCalibD)); - memset(_adcCalibM, 0, sizeof(_adcCalibM)); - anaInEERd(ALLCHAN, SINGLE, 0); - anaInEERd(ALLCHAN, DIFF, 0); - anaInEERd(ALLCHAN, mAMP, 0); - - // setup sclk - anaInConfig(0x18, 0x81, ADC_SCLKBRATE); //reset adc device and sclk byte rate -#endif + Assumes read operation was started and CS line is asserted +END DESCRIPTION **********************************************************/ +#asm +sf_rxbyte:: + ioi ld a,(SCAR) ; start a read operation + ld hl,SCSR ; HL = UART status register +.waitbyte: + ioi ld a,(hl) ; check UART status + and SF_RXRDY_MASK ; char available? + jr z, .waitbyte ; no, wait some more + ioi ld a, (SCDR) ; get received byte + ld l, a + ret +#endasm + +/* START FUNCTION DESCRIPTION ******************************************** +sf_wait_ready + + Wait for chip to finish a pending operation. + + Syntax: int sf_wait_ready (); + + Returns last content of status register +END DESCRIPTION **********************************************************/ +rcm42xx_debug +int sf_wait_ready () +{ +#asm + ld hl,NAPCR + ioi set SF_CS_BIT,(hl) ; assert CS + ld a,0xd7 + ioi ld (SCAR),a ; send read status command + ld hl,SCSR ; HL = UART status register +.sendop: + ioi bit SF_TXIDL_BIT,(hl) + jr nz, .sendop +.rx: + call sf_rxbyte + ld b, a + call sf_rxbyte + ld c, a + and SF_STATRDY_MASK ; chip ready? + jr z, .rx ; no, check again + ld hl,NAPCR + ioi res SF_CS_BIT,(hl) ; deassert CS + ld hl, bc ; return status bytes +#endasm +} + +/* START FUNCTION DESCRIPTION ******************************************** +sf_command + + Send a command to serial flash chip. + + Syntax: void sf_command (int opcode, long addr); + + Parameters: + opcode - command to send in lower byte. + addr - memory address associated with the command + + If high byte of opcode is SF_DEASSERT, the function deasserts CS at the end. + Otherwise CS is left asserted allowing chaining of multiple commands. +END DESCRIPTION **********************************************************/ +rcm42xx_debug +void sf_command (int opcode, long addr) +{ +#asm + ld hl,NAPCR + ioi set SF_CS_BIT,(hl) ; assert CS + ld hl,(sp+@SP+opcode) + ld a,l + ex bc', hl + ioi ld (SCAR),a ; send command opcode + ld hl,SCSR + ld bcde,(sp+@SP+addr) +.sendop: + ioi bit SF_TXE_BIT,(hl) + jr nz, .sendop + ld a,c + ioi ld (SCAR),a ; first (MSB) byte of address +.addr1: + ioi bit SF_TXE_BIT,(hl) + jr nz, .addr1 + ld a,d + ioi ld (SCAR),a ; 2nd byte of address +.addr2: + ioi bit SF_TXE_BIT,(hl) + jr nz, .addr2 + ld a,e + ioi ld (SCAR),a ; 3rd (LSB) byte of address +.addr3: + ioi bit SF_TXIDL_BIT,(hl) ;wait for idle not just buffer empty + jr nz, .addr3 + + ex bc',hl + ld a,h + or a ; END flag set? + jp z, .done ; no + ld hl,NAPCR + ioi res SF_CS_BIT,(hl) ; deassert CS +.done: +#endasm +} + +/*** BeginHeader sf_read_status */ +int sf_read_status (); +/*** EndHeader */ + +/* START FUNCTION DESCRIPTION ******************************************** +sf_read_status + + Send a read status register command and return the two status bytes. + + Syntax: int sf_read_status (); + + Return: content of the 2 status bytes + High byte: + bit 7 Ready/Busy = 1 Device ready + 6 Compare result = 1 Main memory page data does not match buffer data + 5:2 Desnisty code = 1111 (64Mbit) + 1 Sector Prot = 1 Sector protection is enabled + 0 Page Size = 1 Page size is 256 bytes + Low byte: + bit 7 Ready/Busy = 1 Device ready + 5 Erase error = 1 Erase/program error detected + 3 Lockdown = 1 Sector lockdown command enabled + 2 Prog Suspend 2 = 1 A sector is program suspended while using Buffer 2 + 1 Prog Suspend 1 = 1 A sector is program suspended while using Buffer 1 + 0 Erase suspend = 1 A sector is erase suspended. +END DESCRIPTION **********************************************************/ +rcm42xx_debug +int sf_read_status () +{ +#asm + ld hl,NAPCR + ioi set SF_CS_BIT,(hl) ; assert CS + ld a,0xd7 + ioi ld (SCAR),a ; send read status command + ld hl,SCSR ; HL = UART status register +.sendop: + ioi bit SF_TXIDL_BIT,(hl) + jr nz, .sendop + call sf_rxbyte + ld b, a + call sf_rxbyte + ld c, a + ld hl,NAPCR + ioi res SF_CS_BIT,(hl) ; deassert CS + ld hl, bc ; return status bytes +#endasm +} + +/*** BeginHeader sf_read */ +void sf_read (long addr, char __far* dst, long count); +/*** EndHeader */ + +/* START FUNCTION DESCRIPTION ******************************************** +sf_read + + Read bytes from serial flash chip. + + Syntax: void sf_read (long addr, char __far* dst, long count); + + Parameters: + addr - starting byte address + dst - pointer to destination + count - number of bytes to read + + The function issues a "Continous Array Read low frequency" command (0x03) + and then keeps reading successive memory bytes. + + Reading speed is about 1 usec/byte on an RCM4200 +END DESCRIPTION **********************************************************/ +rcm42xx_debug +void sf_read (long addr, char __far* dst, long count) +{ + long page; + int off; + page = addr / sf_rcm4200.pagesize; + off = (int)(addr % sf_rcm4200.pagesize); + addr = (page << sf_rcm4200.pagebitshift) | off; + sf_command (0x03, addr); //continous array read (high frequency) +// sf_rxbyte (); //dummy byte +// sf_rxbyte (); //dummy byte + +#asm + ld iy, SCDR ; UART base address + ioi ld a, (iy) ; clear any leftovers + ld jkhl, (SP+@SP+count) + ld py, jkhl ; PY = counter + ld jkhl, (SP+@SP+dst) +// to gain some speed we do the pointer incrementing and counter decrementing +// while UART is receiving the data. Here we have to decrement the pointer +// to compensate for the incrementing. + ld bcde, 1 + sub jkhl, bcde ; decrement + ld px,jkhl ; PX = destination +.rdloop: + ioi ld a,(iy + SCAR-SCDR) ; start a read operation + ld jkhl, px ; JKHL = destination + add jkhl, bcde ; increment + ld px, jkhl + ld jkhl, py ; JKHL = counter + sub jkhl, bcde ; decrement + ld py, jkhl + test jkhl ; finished? + ex af, af' ; save flags +; next byte is already available by now + ioi ld a, (iy) ; get received byte + ld (px), a ; save it + ex af,af' ; finished? + jr nz, .rdloop ; no + + ld hl,NAPCR + ioi res SF_CS_BIT,(hl) ; deassert CS +#endasm +} + +/*** BeginHeader sf_read_page */ +void sf_read_page (int pagenum, char __far* dst); +/*** EndHeader */ + +/* START FUNCTION DESCRIPTION ******************************************** +sf_read_page + + Read a page from serial flash chip. + + Syntax: void sf_read_page (int pagenum, char __far* dst); + + Parameters: + pagenum - page number to read + dst - pointer to destination + + The function calls sf_read to do the real work. + + Reading speed is about 0.3 msec/page on an RCM4200 +END DESCRIPTION **********************************************************/ +rcm42xx_debug +void sf_read_page (int pagenum, char __far* dst) +{ + long addr; + BitWrPortI (PEDR, &PEDRShadow, 1, 6); + addr = (long)pagenum * sf_rcm4200.pagesize; + sf_read (addr, dst, sf_rcm4200.pagesize); + BitWrPortI (PEDR, &PEDRShadow, 0, 6); +} + +/*** BeginHeader sf_read_id */ +void sf_read_id (char *buf); +/*** EndHeader */ + +/* START FUNCTION DESCRIPTION ******************************************** +sf_read_id + + Read manufacturer and device ID. + + Syntax: void sf_read_id (char *buf); + + Parameter: buf - address of a 5 byte buffer. + + Returns 5 bytes representing manufacturer ID, device ID + and extended device ID. For Adesto AT45DB641E the expected content is: + 0x1F, 0x28, 0x00, 0x01, 0x00 +END DESCRIPTION **********************************************************/ +rcm42xx_debug +void sf_read_id (char *buf) +{ +#asm + ld hl,NAPCR + ioi set SF_CS_BIT,(hl) ; assert CS + ld a,0x9f + ioi ld (SCAR),a ; send read status command + ld hl,SCSR ; HL = UART status register +.sendop: + ioi bit SF_TXIDL_BIT,(hl) + jr nz, .sendop + ld b,5 ; B = byte counter + ld iy, (SP+@SP+buf) ; IY = output buffer +.rx: + call sf_rxbyte ; read byte + ld (iy), a ; save byte + inc iy ; go to next byte in buffer + djnz .rx ; repeat + ld hl,NAPCR + ioi res SF_CS_BIT,(hl) ; deassert CS +#endasm +} + +/*** BeginHeader sf_read_security_reg */ +void sf_read_security_reg (char *buf); +/*** EndHeader */ + +/* START FUNCTION DESCRIPTION ******************************************** +sf_read_security_reg + + Read security register. + + Syntax: void sf_read_security_reg (char *buf); + + Parameter: buf - address of an 128 byte buffer. + + Buffer is filled with 128 bytes representing the content of security register +END DESCRIPTION **********************************************************/ +rcm42xx_debug +void sf_read_security_reg (char *buf) +{ + sf_command (0x77, 0); +#asm + ld iy, (SP+@SP+buf) ;iy = pointr + ld b,128 ; B = byte counter +.rx: + call sf_rxbyte + ld (iy), a ; save byte + inc iy ; go to next byte in buffer + djnz .rx ; repeat + ld hl,NAPCR + ioi res SF_CS_BIT,(hl) ; deassert CS +#endasm +} + +/*** BeginHeader sf_erase_page */ +int sf_erase_page (int pagenum); +/*** EndHeader */ + +/* START FUNCTION DESCRIPTION ******************************************** +sf_erase_page + + Erase a memory page. + + Syntax: int sf_erase_page (int pagenum); + + Parameter: pagenum - page number to erase. + + Return: Last content of status register + + The function waits for the operation to complete. It can take up to 35 msec + (typical 7 ms) for the operation to complete. +END DESCRIPTION **********************************************************/ +rcm42xx_debug +int sf_erase_page (int pagenum) +{ + long addr; + assert (pagenum >=0 && pagenum < sf_rcm4200.pages); + addr = (long)pagenum << sf_rcm4200.pagebitshift; + sf_command (0x81 | SF_DEASSERT, addr); + return sf_wait_ready (); +} + +/*** BeginHeader sf_erase_block */ +int sf_erase_block (int blocknum); +/*** EndHeader */ + +/* START FUNCTION DESCRIPTION ******************************************** +sf_erase_block + + Erase a memory block (8 pages) + + Syntax: int sf_erase_block (int blocknum); + + Parameter: blocknum - block number to erase + + Return: Last content of status register + + The function waits for the operation to complete. It can take up to 50 msec + (typical 25 ms) for the operation to complete. +END DESCRIPTION **********************************************************/ +rcm42xx_debug +int sf_erase_block (int blocknum) +{ + long addr; + assert (blocknum >=0 && blocknum < sf_rcm4200.pages/8); + addr = (long)blocknum << (sf_rcm4200.pagebitshift+3); + sf_command (0x50 | SF_DEASSERT, addr); + return sf_wait_ready (); +} + +/*** BeginHeader sf_erase_sector */ +void sf_erase_sector (int sectnum); +/*** EndHeader */ + +/* START FUNCTION DESCRIPTION ******************************************** +sf_erase_sector + + Erase a sctor (1024 pages). + + Syntax: void sf_erase_sector (int sectnum); + + Parameter: sectnum - sector number to erase + + The function returns imediatley after issuing the 'sector eraase' command. Use + the sf_read_status function to check when the operation is complete. It can + take up to 6.5 seconds (typical 2.5 seconds) for the operation to complete. + + Sector 0 is split in two parts 0a (8 pages) and 0b (1016 pages). The function + erases both parts of sector 0. +END DESCRIPTION **********************************************************/ +rcm42xx_debug +void sf_erase_sector (int sectnum) +{ + long addr; + assert (sectnum >=0 && sectnum < sf_rcm4200.pages/1024); + addr = (long)sectnum << (sf_rcm4200.pagebitshift + 10); + sf_command (0x7f | SF_DEASSERT, addr); + if (sectnum == 0) + { + sf_wait_ready (); + sf_command (0x7f | SF_DEASSERT, 0x001000); + } +} + +/*** BeginHeader sf_erase_chip */ +void sf_erase_chip (); +/*** EndHeader */ + +/* START FUNCTION DESCRIPTION ******************************************** +sf_erase_chip + + Erase entire chip. + + Syntax: void sf_erase_chip (); + + The function returns immediatley after issuing the 'chip eraase' command. Use + the sf_read_status function to check when the operation is complete. It can + take up to 208 seconds (typical 80 seconds) for the operation to complete. +END DESCRIPTION **********************************************************/ +rcm42xx_debug +void sf_erase_chip () +{ + sf_command (0xC7 | SF_DEASSERT, 0x0094809a); +} + +/*** BeginHeader sf_reset */ +void sf_reset (); +/*** EndHeader */ + +/* START FUNCTION DESCRIPTION ******************************************** +sf_reset + + Perform a software reset. + + Syntax: void sf_reset () + + The function issues a 'software reset' command and waits about 35usec + for operation to complete. +END DESCRIPTION **********************************************************/ + +rcm42xx_debug +void sf_reset () +{ + int i; + sf_command (0xF0 | SF_DEASSERT, 0); + //wait about 35usec @ 58MHz +#asm + ld b, 200 + djnz @PC +#endasm +} + +/*** BeginHeader sf_write */ +void sf_write (long addr, char __far* src, long count); +/*** EndHeader */ + +/* START FUNCTION DESCRIPTION ******************************************** +sf_write_buffer + + Write to one of the RAM buffers in serial flash chip. + + Syntax: void sf_write_buffer (int bank, int addr, char __far* src, int count) + + Parameters: + bank - if TRUE use RAM buffer 1. Otherwise use RAM buffer 2 + addr - offset in RAM buffer + src - pointer to source memory area + count - number of bytes to write + + The function issues a 'buffer write' command (0x84 for buffer one or 0x87 for + buffer two) and starts transfering 'count' bytes from 'src'. + + The 'address' parameter specifies the first byte in RAM buffer to be written. + Only the last 'pagesize' bits are significant. +END DESCRIPTION **********************************************************/ +rcm42xx_debug +void sf_write_buffer (int bank, int addr, char __far* src, int count) +{ + sf_command ((bank?0x84 : 0x87), addr); +#asm + ld hl, (SP+@SP+count) + ex bc, hl ; BC = counter + ld jkhl, (SP+@SP+src) + ld px, jkhl ; PX = source buffer + ld hl,SCSR ; HL = UART status +.sendchr: + ld a, (px) +.waitempty: + ioi bit SF_TXE_BIT, (hl) + jr nz, .waitempty + ioi ld (SCAR), a + exx + ld bcde, 1 + ld jkhl, px + add jkhl, bcde + ld px, jkhl + exx + dwjnz .sendchr + +; sent all bytes +.waitidle: + ioi bit SF_TXIDL_BIT,(hl) ;wait for idle not just buffer empty + jr nz, .waitidle + + ld hl,NAPCR + ioi res SF_CS_BIT,(hl) ; deassert CS +#endasm +} + +/* START FUNCTION DESCRIPTION ******************************************** +sf_write + + Write to serial flash. + + Syntax: void sf_write (long addr, char __far* src, long count); + + Parameters: + - addr - destination address in flash memory + - src - address of source buffer + - count - number of bytes to write + + The function starts writing into serial flash RAM buffers then transfers + the content to main memory alternating between the two RAM buffers. +END DESCRIPTION **********************************************************/ +rcm42xx_debug +void sf_write (long addr, char __far* src, long count) +{ + long page, end_page; + int off; + int bsel; //selected buffer + page = addr / sf_rcm4200.pagesize; + off = (int)(addr % sf_rcm4200.pagesize); + end_page = (addr+count) / sf_rcm4200.pagesize; + addr = (long)page << sf_rcm4200.pagebitshift; + if (off || page == end_page) + { + //must read first page in buffer + sf_command (0x53 | SF_DEASSERT, addr); + sf_wait_ready (); + } + bsel = 1; //select buffer 1 + + while (page != end_page) + { + //write page in buffer. First 'off' bytes are unchanged + sf_write_buffer (bsel, off, src, sf_rcm4200.pagesize - off); + sf_wait_ready (); //wait for previus operation to finish + sf_command ((bsel?0x83:0x86) | SF_DEASSERT, addr); //buffer to main memory page + page++; + bsel = !bsel; + count -= sf_rcm4200.pagesize - off; + src += sf_rcm4200.pagesize - off; + addr = (long)page << sf_rcm4200.pagebitshift; + off = 0; //only first page has a non-zero offset + } + if (count) //any leftovers? + { + sf_wait_ready (); + /* if offset is not 0 we had a write operation within a page and + page is already in buffer.*/ + if (!off) + { + //need last page. Read it now + sf_command ((bsel?0x53:0x55) | SF_DEASSERT, addr); + sf_wait_ready (); + } + sf_write_buffer (bsel, off, src, (int)count); + sf_command ((bsel?0x83:0x86) | SF_DEASSERT, addr); //buffer to main memory page + } + sf_wait_ready (); } /*** BeginHeader */ #endif -/*** EndHeader */ \ No newline at end of file +/*** EndHeader */ + diff --git a/Samples/RCM4200/Serial_Flash/SFLASH_INSPECT.C b/Samples/RCM4200/Serial_Flash/SFLASH_INSPECT.C index 75b5753..d4266f0 100644 --- a/Samples/RCM4200/Serial_Flash/SFLASH_INSPECT.C +++ b/Samples/RCM4200/Serial_Flash/SFLASH_INSPECT.C @@ -1,5 +1,6 @@ /* - Copyright (c) 2015, Digi International Inc. + Original work Copyright (c) 2015, Digi International Inc. + Copyright (c) 2021 Mircea Neacsu Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -13,234 +14,379 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + /***************************************************************************** sflash_inspect.c This program is a handy utility for inspecting the contents of a serial -flash chip. When it starts it attempts to initialize a serial flash -chip on serial port C. If one is found then the user can perform five -different commands: +flash chip. It has been modified to work with serial flash functions included +in RCM42xx.LIB + +User can perform a number of different commands: +'b' erases a block (8 pages) +'e' erases a page +'l' lists an address range 'p' prints out the contents of a specified page in the serial flash 'r' prints out the contents of a range of pages from the serial flash -'c' clears (sets to zero) all of the bytes in a specified page 'f' sets all bytes on the specified page to the given value +'s' erases a sector (1024 pages) 't' writes user specified text into a selected page +'w' writes a pattern to an address range +'z' erases the whole chip The program prints out a single line for a page if all bytes in the page are set to the same value. Otherwise it prints a hex/ascii dump of the page. *****************************************************************************/ +//#define RCM42XX_DEBUG #use RCM42xx.lib -//#define SFLASH_DEBUG +char flash_buf[1056]; -#use "sflash.lib" -char flash_buf[1056]; +void erase_flash () +{ + int stat; + long t; + sf_erase_chip (); + printf ("\n"); + t = SEC_TIMER; + while (((stat = sf_read_status()) & SF_STATRDY_MASK) == 0) + { + if (SEC_TIMER > t+1) + { + printf ("."); + t = SEC_TIMER; + } + } + printf ("Done!\n"); +} // Gets positive numeric input from keyboard and returns int value when enter key // is pressed. Returns -1 if non-numeric keys are pressed. (Allows backspace) -int input_number() +long input_number() +{ + long number; + char inchar; + + number = 0; + while(1) + { + inchar = getchar(); + putchar(inchar); //echo input + fflush(stdout); + if(inchar == '\n' || inchar == '\r') + { + return number; + } + else if(inchar == '\b') + { + //backspace + number = number / 10; + } + else if(inchar >= '0' && inchar <= '9') + { + number = number*10 + (inchar - '0'); + } + else + { + //bad input + return -1; + } + } // end of while +} + +void print_command() +{ + printf("Valid commands are:\n" + " B - earse block\n" + " E - erase page\n" + " L - list an address range\n" + " P - print page\n" + " R - print a range of pages\n" + " F - fill a page with a specified value\n" + " S - erase sector\n" + " T - write text into a specified page\n" + " W - write an address range\n" + " Z - erase the whole chip\n\n"); +} + +void list_range (long addr, long count) { - int number; - char inchar; - - number = 0; - while(1) - { - inchar = getchar(); - putchar(inchar); //echo input - fflush(stdout); - if(inchar == '\n' || inchar == '\r') + char __far *buffer; + long i, sz, page; + int off; + sz = count; + buffer = (char __far *)_xalloc (&sz, 0, XALLOC_ANY); + if (sz < count) + { + printf ("\nCannot allocated enough RAM buffer!!\n\n"); + return; + } + sf_read (addr, buffer, count); + i = 0; + page = addr / sf_rcm4200.pagesize; + off = (int)(addr % sf_rcm4200.pagesize); + printf ("\n%5ld - %04x :", page, off); + while (i < count) + { + printf (" %02x", buffer[i++]); + addr++; + page = addr / sf_rcm4200.pagesize; + off = (int)(addr % sf_rcm4200.pagesize); + if (off % 16 == 0) + printf ("\n%5ld - %04x :", page, off); + } + printf ("\n"); + xrelease ((long)buffer, sz); +} + +void write_range (long addr, long count) +{ + char __far *buffer; + long i, sz, page; + int off; + char chr; + sz = count; + buffer = (char __far *)_xalloc (&sz, 0, XALLOC_ANY); + BitWrPortI (PEDR, &PEDRShadow, 0, 6); + if (sz < count) + { + printf ("\nCannot allocate enough RAM buffer!!\n\n"); + return; + } + chr = 0; + for (i=0; i>4) +1) * 16; + for (j = 0, buf = flash_buf; j < k; j++) + { + if (j % 16 == 0) { - //backspace - number = number / 10; + p = linebuf; + p += sprintf (p, "%04x: ", j); } - else if(inchar >= '0' && inchar <= '9') + fbyte = *buf++; + if (j < sf_rcm4200.pagesize) { - number = number*10 + (inchar - '0'); + p += sprintf (p, "%02x ", fbyte); + ascii_buffer[j % 16] = isprint (fbyte) ? fbyte : '.'; } else { - //bad input - return -1; + p += sprintf (p, " "); + ascii_buffer[j % 16] = ' '; } - } // end of while -} -void print_command() -{ - printf("\npress c to clear a page\n"); - printf("press p to print a page\n"); - printf("press r to print a range of pages\n"); - printf("press f to fill a page with a specified value\n"); - printf("press t to write text into a specified page\n\n"); + if (j % 16 == 15) + { + printf ("%s %s\n", linebuf, ascii_buffer); + } + } + } } -int main() + +int main () { - char ascii_buffer[17]; - char fbyte, inchar; - int i, j, k, pagenum, value, start, end; - char linebuf[80], *p, *buf, ch; - - brdInit(); - sfspi_init(); - if (sf_init()) - { - printf("Flash init failed\n"); - exit(-1); - } - else - { - printf("Flash init OK\n"); - printf("# of blocks: %d\n", sf_blocks); - printf("size of block: %d\n\n", sf_blocksize); - } - print_command(); - - while(1) - { - inchar = getchar(); - if(inchar == 'c') + char fbyte, inchar, buf[256]; + char ascii_buffer[20], *pchr; + int pagenum, start, end, i; + long flash_sz, addr, length; + brdInit(); + + sf_reset (); + + sf_read_id (buf); + printf ("Flash ID: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4]); + if (memcmp (buf, "\x1f\x28\x00\x01\x00", 5)) + printf ("\nUNEXPECTED FLASH ID!!!!\n"); + + sf_read_security_reg (buf); + printf ("Security register:\n"); + pchr = ascii_buffer; + for (i=0; i<128; i++) + { + if (i%16 == 0 && i > 0) + { + *pchr = 0; + printf (" %s\n", ascii_buffer); + pchr = ascii_buffer; + } + printf (" %02x", buf[i]); + *pchr++ = isprint(buf[i])? buf[i] : '.'; + } + printf (" %s\n\n", ascii_buffer); + print_command(); + + while (1) + { + printf ("Command? "); + inchar = getchar(); + putchar(inchar); //echo input + inchar = tolower(inchar); + printf ("\n"); + switch (inchar) + { + case 'b': + printf("block number to erase?"); + pagenum = (int)input_number(); + if(pagenum >= 0 && pagenum < sf_rcm4200.pages/8) + { + printf("\nErasing block %d\n", pagenum); + sf_erase_block (pagenum); + } + else + printf("ERROR: invalid block number\n"); + break; + + case 'e': + printf("page number to erase?"); + pagenum = (int)input_number(); + if(pagenum >= 0 && pagenum < sf_rcm4200.pages) + { + printf("\nErasing page %d\n", pagenum); + sf_erase_page (pagenum); + printf ("Done!\n"); + } + else + printf("ERROR: invalid page number\n"); + break; + + case 'l': + printf("Starting address?"); + addr = input_number(); + printf ("\nNumber of bytes?"); + length = input_number (); + list_range (addr, length); + break; + + case 'p': + case 'r': + if (inchar == 'p') { - printf("page number to clear?"); - pagenum = input_number(); - if(pagenum >= 0 && pagenum < sf_blocks) - { - printf("\nClearing page %d\n", pagenum); - memset (flash_buf, 0, sf_blocksize); - sf_writeRAM(flash_buf, 0, sf_blocksize); - sf_RAMToPage(pagenum); - } - else - { - printf("ERROR: invalid page number\n"); - } - } //end if(inchar =='c') - else if((inchar == 'p') || (inchar == 'r')) + // Use start for page to print + printf("Page number to print out?"); + start = (int)input_number(); + // Check that it is a valid page + if(start < 0 || start >= sf_rcm4200.pages) + { + printf("Invalid page number.\n\n"); + continue; + } + // Set single page range for 'p' command + end = start; + } + else { - if (inchar == 'p') { - // Use start for page to print - printf("Page number to print out?"); - start = input_number(); - // Check that it is a valid page - if(start < 0 || start >= sf_blocks) { - printf("Invalid page number.\n\n"); - continue; - } - // Set single page range for 'p' command - end = start; - } - else { - printf("Starting page number to print out?"); - start = input_number(); - // Check that it is a valid page - if(start < 0 || start >= sf_blocks) { - printf("Invalid page number.\n\n"); - continue; - } - printf("\nEnding page number to print out?"); - end = input_number(); - if(end < start || end >= sf_blocks) { - printf("Invalid page number.\n\n"); - continue; - } - } - // Loop through range of pages (range of 1 page for 'p' command) - for (pagenum = start; pagenum <= end; pagenum++) - { - printf("\nPage %d", pagenum); - sf_pageToRAM(pagenum); - sf_readRAM(flash_buf, 0, sf_blocksize); - - // Test if entire buffer filled with a single value - buf = flash_buf; - for (j = k = 0, ch = *buf; j < 512; j++) { - if(ch != *buf++) { - k = 1; - break; - } - } - // See if page is all the same value - if (k) { - printf("\n"); // No, drop through to print data - } - else { // Yes, print out message instead - printf(" ALL = 0x%02x\n", ch); - continue; - } - k = (sf_blocksize & 0xFFF0) + ((sf_blocksize & 0x000F) ? 16 : 0); - ascii_buffer[16] = 0; - for (j = 0, buf = flash_buf; j < k; j++) - { - if (j % 16 == 0) - { - p = linebuf; - p += sprintf (p, "%04x: ", j); - } - fbyte = *buf++; - - if (j >= sf_blocksize) - { - p += sprintf (p, " "); - ascii_buffer[j % 16] = ' '; - } - else - { - p += sprintf (p, "%02x ", fbyte); - ascii_buffer[j % 16] = isprint (fbyte) ? fbyte : '.'; - } - if (j % 16 == 15) - { - printf ("%s %s\n", linebuf, ascii_buffer); - } - } - } - } // end if((inchar =='p') || (inchar == 'r')) - else if(inchar == 'f') + printf("Starting page number to print out?"); + start = (int)input_number(); + // Check that it is a valid page + if(start < 0 || start >= sf_rcm4200.pages) + { + printf("Invalid page number.\n\n"); + continue; + } + printf("\nEnding page number to print out?"); + end = (int)input_number(); + if(end < start || end >= sf_rcm4200.pages) + { + printf("Invalid page number.\n\n"); + continue; + } + } + print_pages (start, end); + break; + + case 'f': + printf("page number to fill with specified value? "); + pagenum = (int)input_number(); + if(pagenum >= 0 && pagenum < sf_rcm4200.pages) { - printf("page number to fill with specified value? "); - pagenum = input_number(); - if(pagenum >= 0 && pagenum < sf_blocks) - { - printf("\nPage %d\n", pagenum); - printf("enter fill value " ); - value = input_number(); - printf("\nValue is %d dec is %02x hex", value,value); - printf("\nFilling page %d with value %02x hex\n", pagenum,value); - memset (flash_buf, value, sf_blocksize); - sf_writeRAM(flash_buf, 0, sf_blocksize); - sf_RAMToPage(pagenum); - } - else - { - printf("ERROR: invalid page number\n"); - } - } // end of if(inchar == 'f') - else if(inchar == 't') + printf("\nPage %d\n", pagenum); + printf("enter fill value (decimal) " ); + fbyte = (int)input_number(); + printf("\nFilling page %d with value 0x%02x\n", pagenum,fbyte); + memset (flash_buf, fbyte, sf_rcm4200.pagesize); + sf_write(pagenum * sf_rcm4200.pagesize, flash_buf, sf_rcm4200.pagesize); + } + else + printf("ERROR: invalid page number\n"); + break; + + case 't': + printf("page number in which to write text? "); + pagenum = (int)input_number(); + if(pagenum >= 0 && pagenum < sf_rcm4200.pages) { - printf("page number in which to write text? "); - pagenum = input_number(); - if(pagenum >= 0 && pagenum < sf_blocks) - { - printf("\nPage %d\n", pagenum); - printf("enter character string followed by RETURN \n" ); - gets (flash_buf); - printf("Storing the following text ==> %s \n",flash_buf); - sf_writeRAM(flash_buf, 0, sf_blocksize); - sf_RAMToPage(pagenum); - } - else - { - printf("ERROR: invalid page number\n"); - } - } // end of if(inchar == 't') + printf("\nPage %d\n", pagenum); + printf("enter character string followed by RETURN \n" ); + gets (flash_buf); + printf("Storing the following text ==> %s \n",flash_buf); + sf_write(pagenum * sf_rcm4200.pagesize, flash_buf, sf_rcm4200.pagesize); + } + else + printf("ERROR: invalid page number\n"); + break; + + case 'w': + printf("Starting address?"); + addr = input_number(); + printf ("\nNumber of bytes to write?"); + length = input_number (); + write_range (addr, length); + break; + + case 'z': + erase_flash (); + break; + + default: print_command(); - } // end of while + break; + } + } // end of while } From e2d7401bb6a78291afe6ece6a60de2482e0d737a Mon Sep 17 00:00:00 2001 From: Mircea Neacsu Date: Fri, 26 Feb 2021 09:48:49 -0500 Subject: [PATCH 2/2] Removed o-scope triggering aids --- Samples/Libraries/RCM42xx.LIB | 2 -- 1 file changed, 2 deletions(-) diff --git a/Samples/Libraries/RCM42xx.LIB b/Samples/Libraries/RCM42xx.LIB index 72b3ac9..f9d638f 100644 --- a/Samples/Libraries/RCM42xx.LIB +++ b/Samples/Libraries/RCM42xx.LIB @@ -560,10 +560,8 @@ rcm42xx_debug void sf_read_page (int pagenum, char __far* dst) { long addr; - BitWrPortI (PEDR, &PEDRShadow, 1, 6); addr = (long)pagenum * sf_rcm4200.pagesize; sf_read (addr, dst, sf_rcm4200.pagesize); - BitWrPortI (PEDR, &PEDRShadow, 0, 6); } /*** BeginHeader sf_read_id */