some notes on nordic's nRF9E5 8051 derivate

This document should be read along with, and was mainly created by reading

memory layout

for programming in assembler you may want to use my nRF9E5 include file.
0xFFFF  |=====================
        |XXXXXXXXXXXXXXXXXXXXX
        |   not addressable   
0x8200  |XXXXXXXXXXXXXXXXXXXXX
        |=====================
0x81FF  |                     
        |                     
        |     boot loader     
        |                     
0x8000  |                     
        |=====================
0x7FFF  |XXXXXXXXXXXXXXXXXXXXX
        |   not addressable   
0x1000  |XXXXXXXXXXXXXXXXXXXXX
4kBytes |=====================
0x0FFF  |                         \
        |                         |
        |   3.75 kBytes           |
        |                         |
0x0100  |                         |
256bytes|=====================    |
0x00ff  |         ||              |   ERAM,
        |  IRAM   ||   SFR        |== program/data mem
        |         ||              |   accessible w/
        | indirect|| direct       |   movc, movx
        | adressin|| addressing   |
        | only    || only         |
0x0080  |         ||              |
128bytes|=====================    |
0x007F  |                         |    \
        |                         |    |
        | variable allocation     |    |
        |                         |    |== direct and indirect
        | --stack-after-data      |    |   addressing
        |   (sdcc)                |    |
0x0030  |                         |    |
        |=====================    |    |
0x002F  |                         |    |
        |                         |    |
        | bit addressable         |    |
        | space                   |    |
        | (bit addresses          |    |
        |  0x00-0x7F)             |    |
0x0020  |                         |    |
        |=====================    |    |
0x001F  | R7                      |    |
        |  - register bank 3      |    |
0x0018  | R0                      |    |
        |---------------------    |    |
0x0017  | R7                      |    |
        |  - register bank 2      |    |
0x0010  | R0                      |    |
        |---------------------    |    |
0x000F  | R7                      |    |
        |  - register bank 1      |    |
0x0008  | R0                      |    |
        |---------------------    |    |
0x0007  | R7                      |    |
        |  - register bank 0      |    |
0x0000  | R0                      |    |
        |=====================    /    /



addressing modes

immediate addressing
	mov	a,	#0x20	; a = x20
direct addressing
	mov	a,	0x20	; a = contents of x20
indirect addressing
	mov	a,	@R1	; a = contents of address in R1
external direct addressing
	movx	a,	@DPTR	; a = contents of 16bit address pointed by DPTR
	movx	@DPTR,	a	; contents of 16bit address pointed by DPTR = a

e.g.: read 0x0FED:
	mov	DPTR,	#0x0FED
	movx	a,	@DPTR
external indirect addressing
	movx	a,	@R1	; read indirect R1 address
	movx	@R1,	a	; write to indirect R1 address
code indirect addressing
	movc	a,	@A+DPTR
	movc	a,	@A+PC

notes on the stack

the stackpointer SP has a resetvalue of 0x07, that means the first push
command will write to 0x08, the R0 register of bank1, the second push
will wirte to 0x09.
To be safe the SP should be initializes by SW to 0x2F (or the highest
used bit-addressable register).
;--------------------------------------------------------
	.area	area_address0 (DATA)
	mov	SP,	#0x2F; stack grows after bit area
	ljmp    start
;--------------------------------------------------------
; our main code lies from 0x0100 on
;--------------------------------------------------------
        .area   area_0x0100 (REL,CON,CODE)
;--------------------------------------------------------
start:
        ...




notes on interrupts

all InterruptServiceRoutines MUST push and pop PSW !
This is the statusword and it is unlikely that the statusword remains
the same during interrupt processing.
IE	0xA8 interrupt enable register
IP	0xB8 interrupt priority register

EEPROM program format

...  |                                       |
...  |                                       |
...  |                                       |
N+1: | Second byte of user program,          |
     | goes into ERAM at 0x0001              |
N:   | First byte of user program,           |
     | goes into ERAM at 0x0000              |
...  |                                       |
...  |                                       |
...  | ignored data                          |
...  |                                       |
...  |                                       |
2:   | Nr of 256 byte blocks in user program |  -> 0x10 -> 4kB
     | (includes block 0 that is not full)   |
1:   | offset to start of user program (N)   |  -> 0x03
0:   | 0 | 0 | 0 | 0 | SPEED | XO_FREQ[2..0] |  -> 0x04 -> 20 MHz

SPEED: EEPROM max. speed
	0 : 1 MHz
	1 : 0.5 MHz
XO_FREQ: crystal oscillator frequency
	000 = 4MHz
	001 = 8MHz
	010 = 12MHz
	011 = 16MHz
	100 = 20MHz



nRF9E5 special function registers (SFRs)

0x80 P0
SP DPL0 DPH0 DPL1 DPH1 DPS PCON 0x87
0x88 TCON
TF1 TR1 TF0 TR0
IE1 IT1 IE0 IT0
TMOD TL0 TL1 TH0 TH1 CKCON SPC_FNC 0x8F
0x90 P1
- - - -
P1_3 P1_2 P1_1 P1_0
EXIF MPAGE P0_DRV P0_DIR P0_ALT P1_DIR P1_ALT 0x97
0x98 SCON
SM0 SM1 SM2 REN
TB8 RB8 TI RI
SBUF 0x9F
0xA0 P2
AM CD DR/TRC_CE CE EOC/TX_EN
RACSN SBMISO SBMOSI SBSCK
0xA7
0xA8 IE
EA 0 ET2 ES
ET1 EX1 ET0 EX0
PWMCON PWMDUTY REGX_MSB REGX_LSB REGX_CTRL 0xAF
0xB0
RSTREAS SPI_DATA SPI_CTRL SPICLK TICK_DV CK_CTRL 0xB7
0xB8 IP
1 0 PT2 PS
PT1 PX1 PT0 PX0
CKLFCON 0xBF
0xC0
0xC7
0xC8 T2CON
TF2 EXF2 RCLK TCLK
EXEN2 TR2 C/T2 CP/RL2
RCAP2L RCAP2H TL2 TH2 0xCF
0xD0 PSW
CY AC F0 RS1
RS0 OV F1 P
0xD7
0xD8 EICON
- 1 0 0
WDTI 0 0 0
0xDF
0xE0 ACC
0xE7
0xE8 EIE
1 1 1 EWDI
EX5 EX4 EX3 EX2
0xEF
0xF0 B
0xF7
0xF8 EIP
1 1 1 PWDI
PX5 PX4 PX3 PX2
HWREV 0xFF
  I/O port SFRs  
   control SFRs  
     other SFRs  
bit addressable SFRs all SFRs dividable by 8 are bit adressable

Special Function Register alphabetical list

(Table 62 from the datasheet)

Register  Addr Reset Description
ACC       0xE0 0x00  Accumulator register
B         0xF0 0x00  B-register
CK_CTRL   0xB6 0x00  Table 51, page 58
CKCON     0x8E 0x01  Table 67, page 78
CKLFCON   0xBF 0x27  Table 43 on page 51
DPH0      0x83 0x00  ch.18.5, page 68
DPH1      0x85 0x00  ch.18.5, page 68
DPL0      0x82 0x00  ch.18.5, page 68
DPL1      0x84 0x00  ch.18.5, page 68
DPS       0x86 0x00  ch.18.5, page 68
EICON     0xD8 0x40  Table 40, page 47
EIE       0xE8 0xE0  Table 41, page 47
EIP       0xF8 0xE0  Table 42, page 48
EXIF      0x91 0x08  Table 39, page 47
HWREV     0xFE 0x00  read only hardware revision no
IE        0xA8 0x00  interrupt enable Table 37, page 46
IP        0xB8 0x80  interrupt priority Table 38, page 46
MPAGE     0x92 0x00  do not use
P0        0x80 0xFF  Table 10, page 15
P0_ALT    0x95 0x00  Table 10, page 15
P0_DIR    0x94 0xFF  Table 10, page 15
P0_DRV    0x93 0x00  Table 10, page 15
P1        0x90 0xFF  Table 12, page 16
P1_ALT    0x97 0x00  Table 12, page 16
P1_DIR    0x96 0xF4  Table 12, page 16
P2        0xA0 0x08  Table 15, page 19
PCON      0x87 0x30  Table 49, page 57
PSW       0xD0 0x00  Table 63, page 72
PWMCON    0xA9 0x00  Table 35, page 44
PWMDUTY   0xAA 0x00  Table 35, page 44
RCAP2H    0xCB 0x00  ch.18.8.3.3, page 80
RCAP2L    0xCA 0x00  ch.18.8.3.3, page 80
REGX_CTRL 0xAD 0x00  Table 45, page 54
REGX_LSB  0xAC 0x00  Table 45, page 54
REGX_MSB  0xAB 0x00  Table 45, page 54
RSTREAS   0xB1 0x02  Table 48, page 56
SBUF      0x99 0x00  ch.18.9, page 81
SCON      0x98 0x00  Table 71, page 82
SP        0x81 0x07  Stack pointer
SPC_FNC   0x8F 0x00  do not use
SPI_CTRL  0xB3 0x00  Table 33, page 43
SPI_DATA  0xB2 0x00  Table 33, page 43
SPICLK    0xB4 0x00  Table 33, page 43
T2CON     0xC8 0x00  Table 68, page 79
TCON      0x88 0x00  Table 66, page 75
TH0       0x8C 0x00  ch.18.8, page 74
TH1       0x8D 0x00  ch.18.8, page 74
TH2       0xCD 0x00  ch.18.8, page 74
TICK_DV   0xB5 0x1D  Table 43, page 51
TL0       0x8A 0x00  ch.18.8, page 74
TL1       0x8B 0x00  ch.18.8, page 74
TL2       0xCC 0x00  ch.18.8, page 74
TMOD      0x89 0x00  Table 65, page 74

SPI interface

The SPI interface is made up by 7 registers:

STATUS      RO
ADC_CONFIG  RW
ADC_DATA    RO
RF_CONFIG   RW
TX_ADDR     RW
TX_DATA     RW
RX_DATA     RO

behind most of these registers lies a sequence of up
to 32 bytes to be read or written via SPI.

What I found missing in the docs is that for full clock speed
one needs not only to set XO_DIRECT in CKLFCON:

mov     CKLFCON,#0xe4   ; - - XOF[5..3] XO_DIRECT UP_CLK_FREQ[1..0]

but also configure RF_CONFIG via SPI (byte 9 after RF_CONFIG).
Since the documentation somewhat shaky says that the SPI register
and CKLFCON should be same, I also set the two MSBs in CKLFCON ...
The registers seem to be different, I am not sure if setting CKLFCON
has any effect at all.


fixes for nRF9E5rev1_1.pdf

nRF9E5rev1_1.pdf:

In Table 21 the LSB SCON.0 bit is missing, it is the
	"ring indicator" RI bit, which is set high
	once a valid byte is received. Must be cleared by SW.

nRF9E5rev1_2.pdf
nordic found some formerly undocumented bits and docu bugs:
- SPEED bit in the EEPROM was messd up
- UP_CLK_EN is now known as XO_DIRECT

some general notes on 8051s


Note: all ISRs need to push + pop PSW !
Note: SP should be initialzed to 0x2F by SW to be safe
Note: to switch between DPL0/DPH0 and DPL1/DPH1 as active DPTR
      use the DPS register bit0 (all other DPS bits have no function)
Note: to use the UART you need to configure SCON,
      and timer1 in TCON, and TMOD
Note: MOV A,#20h   ; requires 2 instruction cycles
      MOV 0xE0,#20h ; requires 3 instruction cycles
Note: 
      PC cannot be written, but LJMP 0x0123 does the trick,
      PC cannot be read, but there's a trick to reveal its value: FIXME