Full Version : Kuba's Z8 Bootloader (ZiLOG)
avr >>PIC 8051 ZILOG ARM TI H8 ETC >>Kuba's Z8 Bootloader (ZiLOG)


Admin5- 04-21-2006
When using DMA with UART, you should periodically poll the error bits (UxSTAT0 & 0x78) and if any of them is set, do two dummy reads of UxRXD. Two reads are needed to clear OE, and it's faster to do two in a row than to test specifically for OE.

Since the DMA transfer is essentially stuck as soon as errors occur, you have to do this polling somewhere in your loop so that things get un-stuck . Errors usually occur when you connect/disconnect things.

Nominally, the error flag checking can be done in the interrupt. You'd set RDAIRQ# (in UxCTL1) to 1 so that only receiver errors generate a real interrupt, while data transfers only strobe the DMA.

I made a small mistake in my firmware design. I used an interrupt driven communications model to communicate with the PC host. Of course that is problematic since the flash loader can't use any of the interrupt vectors; they must remain available for use by the application when it gets loaded.

There's an easy way around this limitation: use DMA. There's no need to handle any DMA interrupts, just keep a big enough buffer and you'll be fine. Interrogate DMAxHS (see below) to see what's the current position of the write 'head'.


CODE

#define DMA0HS (*(volatile far unsigned int*)&DMA0H)
#define DMA1HS (*(volatile far unsigned int*)&DMA1H)

...
far char * head;

asm("ATM");
head = DMAxHS & 0x0FFF; // this translates to decent assembly



note that this is a flash programmer, not boot loader -- as pointed out by someone, the boot loader uses a flash programmer but provides much more beyond that.

CODE


;  386   void near programFlash(far char * src, rom char * dst, UINT count)
;  388      UCHAR zero = 0;
  CLR   R1
;  394       page = (UCHAR)((UINT)dst >> 9);
  LD   R0,_1_programFlash
  SRL   R0
;  395       FCTL = zero;
  LDX   4088,R1
;  396       FPS = page; FCTL = 0x73; FCTL = 0x8C; FPS = page;
  LDX   4089,R0
  LDX   4088,#115
  LDX   4088,#140
  LDX   4089,R0
;  397       FCTL = 0x95; // erase the page
  LDX   4088,#149
;  398       FCTL = zero;
  LDX   4088,R1
;  399       FPS = page; FCTL = 0x73; FCTL = 0x8C; FPS = page;
  LDX   4089,R0
  LDX   4088,#115
  LDX   4088,#140
  LDX   4089,R0
;  400       // program
;  401       s = src; d = dst;
  LD   R0,_2_programFlash
  LD   R1,_2_programFlash+1
  LD   R2,_1_programFlash
  LD   R3,_1_programFlash+1
;  402       do {
_10_L_210:
;  403           *d = *s;
  LDX   R4,@RR0
  LDC   @RR2,R4
;  404         ++ d;
  INCW   RR2
;  405         ++ s;
  INCW   RR0
;  406         -- count;
  SUB   _0_programFlash+1,#1
  SBC   _0_programFlash,#0
;  407       } while (nonzero(count));
  LD   R4,_0_programFlash
  OR   R4,_0_programFlash+1
  JR   NE,_10_L_210
;  408      FCTL = 0; //relock
       LDX   4088,#-0
       RET



The code below should work with ZDS II 4.9.5. It will most likely give very sloppy code when run under any other version, so DON'T

Ah, don't be fooled -- this is written in assembly. Yes, assembly. You put it into a .c file and run a compiler on it, but it's still assembly. You'll see what I mean when you look at the .src that the compiler generates (enable it in project options: Compiler->Listings). The whole thing is a big workaround for optimizer deficiencies, but it should be easy to see what I did and why.

If any of you can get the resultant .src any slimmer than what it already is while still feeding readable C code to the compiler, I'd like to see it. It's always nice to learn new tricks.

Note that for near data and/or counts <= 255, you copy count into a register as well, and obtain code that is literally as good handwritten assembly.


CODE

#include <ez8.h>
#include <defines.h>

// Do not compile with anything else but ZDS II 4.9.5
// if you want the code to perform reasonably well.
// DO NOT change the code without verifying the .src
// output first, otherwise you WILL get bitten.

// This is a workaround for some compiler
// writers not knowing some easy assembly tricks.;)
#define nonzero(i) ((UCHAR)(i >> 8) | (UCHAR)i)

// programs one page of flash
void near programFlash(far char * src, rom char * dst, UINT count)
{
   UCHAR zero = 0;
   UCHAR page;
   far char * s;
   rom char * d;

   // unlock & wipe page
   page = (UCHAR)((UINT)dst >> 9);
   FCTL = zero;
   FPS = page; FCTL = 0x73; FCTL = 0x8C; FPS = page;
   FCTL = 0x95; // erase the page
   FCTL = zero;
   FPS = page; FCTL = 0x73; FCTL = 0x8C; FPS = page;
   // program
   s = src; d = dst;
   do {
       *d = *s;
       ++ d;
       ++ s;
       -- count;
   } while (nonzero(count));
   // relock
   FCTL = 0;
}







Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.