Page 1 of 1

IAP Demo - erasing / writing flash memory etc.

Posted: Wed Jun 06, 2012 1:16 pm
by cfbsoftware
Main Module - IAPDemo.mod:

Code: Select all

MODULE IAPDemo;
(* =========================================================================  
   Example Cortex-M3 Oberon Program  
  
   Description:
     Uses the LPC1000 on-chip IAP functions to perform the following:
     
     1. Display the part identification number 
     2. Display the boot code version number
     3. Display the unique device serial number
     4. Display the last sector details
     5. Fill the last sector with 0AAH 
     6. Blank check the last sector
     7. Prepare the last sector
     8. Erase the last sector
     9. Blank check the last sector again
    10. Compare a range of identical bytes
    11. Compare a range of dissimilar bytes
  
   Astrobe for Cortex-M3 Version: 
      v4.2 or later
   
  Target:
     All supported LPC13xx / LPC17xx systems
     
   References: 
     The chapter titled: LPC13xx Flash memory programming firmware
       NXP UM10375 LPC1311/13/42/43 User manual

     The chapter titled: LPC17xx Flash memory interface and programming
       NXP UM10360 LPC17xx User manual
       
     Oberon for Cortex-M3 Microcontrollers: Library Modules > IAP
   
   (c) 2010-2012 CFB Software   
   http://www.astrobe.com  
 
 ========================================================================= *)

IMPORT Device, IAP, Out, Main, MAU, MCU, SYSTEM;


PROCEDURE OutLabel(label: ARRAY OF CHAR);
(* Pad the label with trailing blanks and a colon *)
VAR
  str: ARRAY 16 OF CHAR;
  i: INTEGER;
BEGIN
  str := "             : ";
  FOR i := 0 TO LEN(label) - 1 DO 
    str[i] := label[i]
  END;
  Out.String(str)
END OutLabel;


PROCEDURE ShowPartID;
VAR
  id: INTEGER;
BEGIN
  IAP.ReadPartID(id);
  OutLabel("Device Id"); Out.Hex(id, 9); Out.Ln;
  OutLabel("Device Name"); 
  Out.String("LPC"); Out.Int(Device.name, 0);
  Out.Ln()
END ShowPartID;
  

PROCEDURE OutVersionNumber(version: INTEGER);
VAR
  major, minor: INTEGER;
BEGIN
	major := version MOD 010000H DIV 100H;
  minor := version MOD 100H;
  Out.Int(major, 0); 
  Out.Char(".");
  IF minor < 10 THEN Out.Char("0") END;
  Out.Int(minor, 0)
END OutVersionNumber;


PROCEDURE ShowBootVersion;
VAR
  version: INTEGER;
BEGIN
  IAP.ReadBootVersion(version);
  OutLabel("Version Code"); Out.Hex(version, 9); Out.Ln;
  OutLabel("Version No"); OutVersionNumber(version); Out.Ln
END ShowBootVersion;


PROCEDURE ShowUniqueID;
VAR
  id: IAP.UniqueID;
  i: INTEGER;
BEGIN
  IAP.ReadUniqueID(id);
  OutLabel("UniqueID");
  FOR i := 0 TO LEN(id) - 1 DO 
    Out.Hex(id[i], 9);
    Out.Char(" ")
  END;
  Out.Ln
END ShowUniqueID;


PROCEDURE ShowLastSector();
VAR
  lastSector, size, addr: INTEGER;
BEGIN
  lastSector := Device.sectorCount;
  addr := Device.SectorStartAddr(lastSector);
  size := Device.SectorSize(lastSector);
  OutLabel("Last sector");
  Out.String("No = "); Out.Int(lastSector, 0);
  Out.String(", Address = "); Out.Hex(addr, 0);
  Out.String(", Size = "); Out.Int(size, 0);
  Out.Ln()
END ShowLastSector;


PROCEDURE ShowStatus(msg: ARRAY OF CHAR; status: INTEGER);
BEGIN
  OutLabel(msg);
  IF status = 0 THEN 
    Out.String("OK")
  ELSE 
    Out.String("Error code ");
    Out.Int(status, 0)
  END;
  Out.Ln
END ShowStatus;


PROCEDURE CheckBlankLastSector();
VAR
  offset, contents, status, lastSector: INTEGER;
BEGIN
  lastSector := Device.sectorCount;
  status := IAP.BlankCheckSectors(lastSector, lastSector, offset, contents);
  ShowStatus("CheckBlank", status);
  IF status = IAP.SectorNotBlank THEN
    OutLabel("Results");
    Out.String("Offset = "); Out.Hex(offset, 10); 
    Out.String(", Contents = "); Out.Hex(contents, 10);
    Out.Ln
  END;
END CheckBlankLastSector;


PROCEDURE CompareBytes(addr1, addr2, nBytes: INTEGER);
VAR
  offset, status: INTEGER;
BEGIN
  status := IAP.CompareBytes(addr1, addr2, nBytes, offset);
  ShowStatus("Compare", status);
  IF status = IAP.CompareError THEN 
    OutLabel("Results");
    Out.String("Offset = "); Out.Hex(offset, 10); Out.Ln
  END
END CompareBytes;


PROCEDURE EraseLastSector();
VAR
  lastSector: INTEGER;
BEGIN
  lastSector := Device.sectorCount;
  ShowStatus("Prepare", IAP.PrepareSectors(lastSector, lastSector));
  ShowStatus("Erase", IAP.EraseSectors(lastSector, lastSector, MCU.CCLK))
END EraseLastSector;

PROCEDURE MaxBlockSize(): INTEGER;
(* IAP.WriteFlash requires blocks to be written to be one of four sizes *)
(* Choose the largest that can be used as a dynamic local array         *)
VAR
  i: INTEGER;
  sizes: ARRAY 5 OF INTEGER;
BEGIN
  sizes[0] := 4096;
  sizes[1] := 1024;
  sizes[2] := 512;
  sizes[3] := 256;
  sizes[4] := 0;
  i := 0;
  WHILE (i <= 3) & (sizes[i] > MAU.MemAvailable()) DO
    INC(i)
  END;
  RETURN sizes[i]
END MaxBlockSize;  


PROCEDURE FillLastSector(value: CHAR);
(* Fill the last sector of flash RAM with value *)
VAR 
  i, srcAddr, destAddr, lastSector, nBlocks, nBytes, blockSize: INTEGER;
  block: ARRAY OF CHAR;
BEGIN
  blockSize := MaxBlockSize();
  NEW(block, blockSize); 
  lastSector := Device.sectorCount;
  nBytes := Device.SectorSize(lastSector);
  destAddr := Device.SectorStartAddr(lastSector);
  FOR i := 0 TO blockSize - 1 DO 
    block[i] := value
  END;
  srcAddr := SYSTEM.ADR(block);
  nBlocks := nBytes DIV blockSize;
  OutLabel("WriteFlash");
  Out.String("srcAddr = "); Out.Hex(srcAddr, 0); 
  Out.String(", destAddr = "); Out.Hex(destAddr, 10);
  Out.Ln();
  OutLabel(""); 
  Out.String("blockSize = "); Out.Int(blockSize, 0); 
  Out.String(", nBlocks = "); Out.Int(nBlocks, 0); 
  Out.Ln(); 
  FOR i := 0 TO nBlocks - 1 DO
    ShowStatus("Prepare", IAP.PrepareSectors(lastSector, lastSector));
    ShowStatus("WriteFlash", IAP.WriteFlash(srcAddr, destAddr, blockSize, MCU.CCLK));
    destAddr := destAddr + blockSize
  END 
END FillLastSector;


BEGIN
  ShowPartID();
  ShowBootVersion();
  ShowUniqueID();
  ShowLastSector();
  FillLastSector(0AAX);
  CheckBlankLastSector();
  EraseLastSector();
  CheckBlankLastSector();
  CompareBytes(01000H, 01000H, 256);
  CompareBytes(01000H, 02000H, 256)
END IAPDemo.
Device.def

Code: Select all

DEFINITION MODULE Device;

IMPORT IAP;

VAR 
  (* Number of sectors of flash memory *)
  sectorCount*, 
  (* MCU Target name e.g. 1343, 1755 etc. identified
     by using IAP to read the PartID
  *)
  name*: INTEGER;

PROCEDURE* SectorStartAddr*(sectorNo: INTEGER): INTEGER;
(* Sectors 0..15 are 4KB, Sectors 16..29 are 32KB *)

PROCEDURE* SectorSize*(sectorNo: INTEGER): INTEGER;
(* Sectors 0..15 are 4KB, Sectors 16..29 are 32KB *)
   
END Device.
Device.mod:

Code: Select all

MODULE Device;
(* =========================================================================  
   Astrobe for Cortex-M3 Library Functions for device-specific features  
  
   Target:
     All supported LPC13xx / LPC17xx systems
     
   (c) 2012 CFB Software   
   http://www.astrobe.com  
 
 ========================================================================= *)

IMPORT IAP;

VAR 
  id: INTEGER;
  sectorCount*, name*: INTEGER;

PROCEDURE* Init(id: INTEGER; VAR name, sectorCount: INTEGER);
BEGIN
  IF id = 02C40102BH THEN
    name := 1313;  
    sectorCount := 7
  ELSIF id = 03D00002BH THEN 
    name := 1343;  
    sectorCount := 7
  ELSIF id = 025001118H THEN 
    name := 1751;  
    sectorCount := 7
  ELSIF id = 025001121H THEN 
    name := 1752;  
    sectorCount := 15
  ELSIF id = 025011722H THEN 
    name := 1754;  
    sectorCount := 17
  ELSIF id = 025011723H THEN 
    name := 1756;  
    sectorCount := 21
  ELSIF id = 025013F37H THEN 
    name := 1758;  
    sectorCount := 29
  ELSIF id = 025113737H THEN 
    name := 1759;  
    sectorCount := 29
  ELSIF id = 026012033H THEN 
    name := 1763;  
    sectorCount := 21
  ELSIF id = 026011922H THEN 
    name := 1764;  
    sectorCount := 17
  ELSIF id = 026013733H THEN 
    name := 1765;  
    sectorCount := 21
  ELSIF id = 026013F33H THEN 
    name := 1766;  
    sectorCount := 21
  ELSIF id = 026012837H THEN 
    name := 1767;  
    sectorCount := 29
  ELSIF id = 026013F37H THEN 
    name := 1768;  
    sectorCount := 29
  ELSIF id = 026113F37H THEN 
    name := 1769;  
    sectorCount := 29
  END 
END Init;


PROCEDURE* SectorStartAddr*(sectorNo: INTEGER): INTEGER;
(* Sectors 0..15 are 4KB, Sectors 16..29 are 32KB *)
VAR 
  addr: INTEGER;
BEGIN
  ASSERT(sectorNo >= 0, 20);
  ASSERT(sectorNo <= sectorCount, 21);
  IF sectorNo < 16 THEN 
    addr := 00001000H * sectorNo
  ELSE 
    addr := 00010000H + ((sectorNo - 16) * 08000H)
  END;
  RETURN addr
END SectorStartAddr;


PROCEDURE* SectorSize*(sectorNo: INTEGER): INTEGER;
(* Sectors 0..15 are 4KB, Sectors 16..29 are 32KB *)
VAR 
  nBytes: INTEGER;
BEGIN
  ASSERT(sectorNo >= 0, 20);
  ASSERT(sectorNo <= sectorCount, 21);
  IF sectorNo < 16 THEN 
    nBytes := 4 * 1024
  ELSE 
    nBytes := 32 * 1024
  END;  
  RETURN nBytes
END SectorSize;
    
    
BEGIN
  IAP.ReadPartID(id); 
  Init(id, name, sectorCount)
END Device.
Typical Output (run on a Coridium SuperPRO development board):
IAPDemo.png
IAPDemo.png (16.48 KiB) Viewed 18775 times