William,
I read Lewin Edwards excellent book (see my review at amazon.com), and adapted his EB40 example code for the EB40A. Here is the source. I build and execute this code under Cygwin and WinXP. I hope it works for you and helps you get started with polled serial I/O on the EB40A.
Please notice that I use .gdbinit (below) to configure and download via gdb, and I execute ./load.sh (below) to initiate a download. This runs gdb, loads my newly built EB40A program, and produces a gdb prompt. I enter 'cont' (or 'continue') at the gdb prompt and my EB40A application runs. I can interact with it from a terminal connected to the serial port.
If you get it working, and enter 'asdf' at the terminal, the program output should be:
startup ok [00000000] rx = 'a' [00000001] rx = 'd' [00000002] rx = 's' [00000003] rx = 'f'
Please note that I regard this as weekend experimental code. I would not base a commercial product on polled I/O, or this unproven sample code.
I have not taken the time to figure out how to do interrupt driven I/O on the EB40A, but I have a colleague who has this working. I'll ping him and see if he is interested in posting his code. I don't know if he has a minimal enough version, independent of his full product, to be useful to EB40A experimenters in the newsgroup.
Good luck.
Jim
------------------------------------------------------------------------ Makefile
------------------------------------------------------------------------
# Makefile for load.elf
CFLAGS = -g -I. -mcpu=arm7tdmi ASFLAGS = -mcpu=arm7tdmi -gstabs LDFLAGS = -Teb40a-ram.ld -nostartfiles -Lgcc -L. OBJS = boot.o main.o EXE = load.elf
$(EXE): $(OBJS) arm-elf-gcc $(LDFLAGS) -o $(EXE) $(OBJS)
boot.o: boot.s arm-elf-as $(ASFLAGS) -o boot.o boot.s
main.o: main.c eb40a.h serial.h arm-elf-gcc -c $(CFLAGS) -o main.o main.c
clean: rm -f $(OBJS) rm -f $(EXE)
------------------------------------------------------------------------ eb40a-ram.ld
------------------------------------------------------------------------
/* eb40a-ram.ld */
ENTRY(vectors) SEARCH_DIR(.)
MEMORY { sram : org = 0x00010000, len = 0x00040000 }
SECTIONS { .text : { *(.text); . = ALIGN(4); *(.rodata*); . = ALIGN(4); *(.glue_7t); . = ALIGN(4); *(.glue_7); . = ALIGN(4); etext = .; } > sram .data ADDR(.text) + SIZEOF(.text) : { __data_start__ = .; *(.data) . = ALIGN(4); __data_end__ = .; edata = .; _edata = .; } .bss ADDR(.data) + SIZEOF(.data) : { __bss_start__ = .; *(.bss); *(COMMON) __bss_end__ = .; _stack_bottom = .; . += 0x800; _stack_top = .; } end = .; _end = .; __end__ = .; .stab 0 (NOLOAD) : { [ .stab ] } .stabstr 0 (NOLOAD) : { [ .stabstr ] } }
------------------------------------------------------------------------ boot.s
------------------------------------------------------------------------
@ boot.s -- init and call C main() on EB40A
.section .text .code 32 .globl vectors
vectors: b reset b . b . b . b . b . b . b . reset:
@clear .bss section ldr r1,bss_start ldr r2,bss_end ldr r3,=0 clear_bss: cmp r1,r2 strne r3,[r1],#+4 bne clear_bss
@init stack pointer ldr r13,stack_pointer
@call main bl main
@loop forever if main() exits b vectors
stack_pointer: .word _stack_top bss_start: .word __bss_start__ bss_end: .word __bss_end__
------------------------------------------------------------------------ eb40a.h
------------------------------------------------------------------------
/* eb40a.h -- AT91EB40A / AT91R40008 */
/* register and field names based on AT91R40008 PDF */
#ifndef _EB40A_H #define _EB40A_H
#define EB40A_MCKI 66000000 // 66 MHz master clock
#define PS_BASE 0xffff4000 // power save base register #define PS_PCER 0x04 // peripheral clock enable reg #define PS_PCER_US1 0x00000008 // USART1 clock enable
#define PIO_BASE 0xffff0000 // PIO controller base register #define PIO_PDR 0x04 // PIO disable register #define PIO_SODR 0x30 // PIO set output data register #define PIO_CODR 0x34 // PIO clear output data register
#define PIO_TXD1 0x00200000 // USART1 transmit data signal #define PIO_RXD1 0x00400000 // USART1 receive data signal
#define LED_D1 0x00010000 // eb40a led 1 #define LED_D2 0x00020000 // eb40a led 2 #define LED_D3 0x00040000 // eb40a led 3 #define LED_D4 0x00080000 // eb40a led 4 #define LED_D5 0x00000008 // eb40a led 5 #define LED_D6 0x00000010 // eb40a led 6 #define LED_D7 0x00000020 // eb40a led 7 #define LED_D8 0x00000040 // eb40a led 8
#define LED_ALL 0x000f0078 // eb40a leds 1-8
#define WRITEREGW(addr,value) \ *((volatile unsigned int *) (addr)) = (value) #define WRITEREGH(addr,value) \ *((volatile unsigned short *) (addr)) = (value) #define WRITEREGB(addr,value) \ *((volatile unsigned char *) (addr)) = (value)
#define READREGW(addr) \ (*((volatile unsigned int *) (addr))) #define READREGH(addr) \ (*((volatile unsigned short *) (addr))) #define READREGB(addr) \ (*((volatile unsigned char *) (addr)))
#endif
// end.
------------------------------------------------------------------------ serial.h
------------------------------------------------------------------------
/* serial.h -- AT91EB40A / AT91R40008 */
/* register and field names based on AT91R40008 PDF */
#ifndef _SERIAL_H #define _SERIAL_H
#define USART0_BASE 0xfffd0000 // USART0 base register #define USART1_BASE 0xfffcc000 // USART1 base register
#define US_CR 0x00 // control register #define US_MR 0x04 // mode register #define US_IER 0x08 // interrupt enable register #define US_IDR 0x0c // interrupt disable register #define US_IMR 0x10 // interrupt mask register #define US_CSR 0x14 // channel status register #define US_RHR 0x18 // receiver holding register #define US_THR 0x1c // transmitter holding register #define US_BRGR 0x20 // baud rate generator register #define US_RTOR 0x24 // receiver timeout register #define US_TTGR 0x28 // transmitter time guard register #define US_RES1 0x2c // reserved #define US_RPR 0x30 // receive pointer register #define US_RCR 0x34 // receive counter register #define US_TPR 0x38 // transmit pointer register #define US_TCR 0x3c // transmit counter register
#define US_RSTRX 0x00000004 // reset receiver #define US_RSTTX 0x00000008 // reset transmitter
#define US_CHRL_8 0x000000c0 // 8 bits #define US_PAR_NO 0x00000800 // parity none #define US_DBSTOP_1 0x00000000 // 1 stop bit
#define US_RXRDY 0x00000001 // enable RXRDY interrupt #define US_TXRDY 0x00000002 // enable TXRDY interrupt
#define US_RXEN 0x00000010 // receiver enable #define US_TXEN 0x00000040 // transmitter enable
#endif
/* end */
------------------------------------------------------------------------ main.c
------------------------------------------------------------------------
// ----------------------------------------------- // // File: main.c // // Platform: Atmel AT91EB40A // // Processor: AT91R40008 ARM7TDMI // // Date: 8 Aug 2003 // // Desc: Demonstrate polled serial operation. // // ----------------------------------------------- //
#include #include
#include "eb40a.h" #include "serial.h"
static void ser_init(int); static void ser_putc(char); static int ser_getc(void); static void ser_puts(char *);
static void led_on(int); static void led_off(int);
int main(void) { int c; unsigned int counter = 0; char iobf[32];
led_off(LED_ALL);
ser_init(38400);
led_on(LED_D1);
ser_puts("startup ok\r\n");
for (;;) { if ((c = ser_getc()) != -1) { sprintf(iobf, "[%.8u] rx = '%c'\r\n", counter++, isprint(c) ? c : '.'); ser_puts(iobf); } } }
static void ser_init(int baudrate) { int base = USART1_BASE;
// enable clock input to baud rate gen (power saving) WRITEREGW(PS_BASE + PS_PCER, PS_PCER_US1);
// PIO disable (enable peripheral control) USART1 TX RX WRITEREGW(PIO_BASE + PIO_PDR, PIO_TXD1 | PIO_RXD1);
// reset transmitter and receiver WRITEREGW(base + US_CR, US_RSTTX | US_RSTRX);
// set serial mode to N/8/1 WRITEREGW(base + US_MR, US_PAR_NO | US_CHRL_8 | US_DBSTOP_1);
// set baud rate WRITEREGW(base + US_BRGR, EB40A_MCKI / (16 * baudrate));
// disable all interrupts for this serial port WRITEREGW(base + US_IDR, 0xFFFFFFFF);
// enable transmitter and receiver WRITEREGW(base + US_CR, US_TXEN | US_RXEN); }
static void ser_putc(char c) { // wait for transmit holding buffer empty while (!(READREGW(USART1_BASE + US_CSR) & US_TXRDY)) ;
WRITEREGW(USART1_BASE + US_THR, (int) c); }
static int ser_getc(void) { if (!(READREGW(USART1_BASE + US_CSR) & US_RXRDY)) return -1; return READREGW(USART1_BASE + US_RHR); }
static void ser_puts(char *s) { while (*s) ser_putc(*(s++)); }
static void led_on(int led) { WRITEREGW(PIO_BASE + PIO_CODR, led); }
static void led_off(int led) { WRITEREGW(PIO_BASE + PIO_SODR, led); }
// end.
------------------------------------------------------------------------ .gdbinit
------------------------------------------------------------------------
# .gdbinit set remotebaud 115200 target rdi com1 load
------------------------------------------------------------------------ load.sh
------------------------------------------------------------------------
#!/usr/bin/bash # load.sh arm-elf-gdb load.elf
------------------------------------------------------------------------