diff --git a/README b/README index 623e1cf..5c7d5ee 100644 --- a/README +++ b/README @@ -1,17 +1,32 @@ -Right, I know...Got my raspberry pi today. - This repo serves as a collection of low level examples. No operating -system, embedded or low level embedded or deeply embedded, whatever -your term is for this. - -From what we know so far there is a gpu on chip that boots off of I -assume an on chip rom. This goes to the sd card and does things. it -appears that the entry point for us as programmers is the kernel.img -file, which appears to be the memory image copied into the ARM memory -before releasing reset on the ARM processor. The name of course because -this is intended to be a Linux based educational computer, but it is -just a file name, just a memory image. +system, embedded or low level embedded or deeply embedded or bare metal, +whatever your term is for this. + +I am in no way shape or form associated with the raspberry pi organization +nor broadcom. I just happen to own one (some) and am sharing my +experiences. The raspberry pi is about education, and I feel low +level education is just as important as Python programming. + +From what we know so far there is a gpu on chip which: + +1) boots off of an on chip rom of some sort +2) reads the sd card and looks for additional gpu specific boot files +bootcode.bin, loader.bin, start.elf in the root dir of the first partition +(fat formatted) +3) in the same dir it looks for config.txt which you can do things like +change the arm speed from the default 700MHz, change the address where +to load kernel.img, and many others +4) it reads kernel.img the arm boot binary file and copies it to memory +5) releases reset on the arm such that it runs from the address where +the kernel.img data was written + +I have tried a few things for example incorrectly assuming kernel.img +was loaded at address 0x00000000 as a default. If you tell it zero you +still get 0x8000. The arm and gpu share memory I am guessing the gpu +is using that first part of memory, dont really know. 0x8000 being +familiar to linux folks and this is intended to be first a linux +computer so this makes sense. You will want to go here http://elinux.org/RPi_Hardware @@ -22,46 +37,87 @@ And the schematic for the board http://www.raspberrypi.org/wp-content/uploads/2012/04/Raspberry-Pi-Schematics-R1.0.pdf (might be an old link, find the one on the wiki page) -The manual uses addresses like 0x7Exxxxxx, which is the real address for -something. But there is an address translation layer between the ARM -physical address and the real address. All of this code will use the -ARM physical address which is 0x20xxxxxx. The rest of the address is -the same so if the manual says 0x7E123456, then from the ARM use 0x20123456 - -I dont normally use .data nor gcc libraries nor C libraries so you can -build most if not all of my examples using a gcc cross compilerl. Basically +Early in the BCM2835 document you see a memory map. I am going to +operate based on the middle map, this is how the ARM comes up. The +left side is the system which we dont have direct access to in that +form, the gpu probably, not the ARM. The ARM comes up with a memory +space that is basically 0x40000000 bytes in size as it mentions in +the middle chart. 256MBytes is 0x10000000, I am guessing they gave +room to add memory as peripherals are mapped into arm address space at +0x20000000. When you see 0x7Exxxxxx in the manual replace that with +0x20xxxxxx as your ARM physical address. Experimentally I have seen +the memory repeats every 0x40000000, read 0x40008000 and you see the +data from 0x8000. I wouldnt rely on this, just an observation (likely +ignoring the upper address bits in the memory controller). + +Now this memory map shows that somewhere within the SDRAM address space +there is a boundary between the ARM memory in the lower addresses and +the GPU memory in the upper addresses. That boundary is not explained +in that document. There are at the moment three gpu start.elf files +to choose from. A or the difference between them is where this boundary +lies. The default is a 50/50 split the arm gets 128MBytes, and the gpu +128MBytes. arm224_start.elf for example gives 224MBytes to the ARM +and 32MBytes to the GPU. They say that you dont get full gpu performance +if you limit the gpu memory this much. These examples are all going +to assume that the ARM only has 128MBytes and the default boot setting +of 0x8000 for the kernel_address. + +I do not normally use .data nor gcc libraries nor C libraries so you can +build most if not all of my examples using a gcc cross compiler. Basically it doesnt matter if you use arm-none-linux-gnueabi or arm-none-eabi. -what was formerly codesourcery.com still has a LITE version of their +What was formerly codesourcery.com still has a LITE version of their toolchain which is easy to come by, easy to install and well maybe not easy to use but you can use it. Building your own toolchain from gnu -sources (binutils and gcc) is fairly straight forward and at some point -will create a script to do that for you. +sources (binutils and gcc) is fairly straight forward see the build_gcc +directory for a build script. As far as we know so far the Raspberry Pi is not "brickable". Normally -what brickable means is the processor relies on a boot flash. For example -there may be a bootloader that allows you to re-program the flash. If you -make a mistake writing code at this low level and load the boot flash -with that bad code you may not be able to reload the flash again. There -are many ways to prevent this, but there are also still boards that -can be bricked or at least require more equipment or soldering, etc to -recover them. They way this board works is quite interesting. There -is a GPU on chip that boots from an on chip flash (in that respect it -may be brickable, but we dont have access to that GPU boot loader). The -GPU on chip bootloader looks for an sd card, the sd card contains more -GPU code. That code probably initializes sdram, and then copies the -contents of kernel.img on the sd card to sdram. Then releases reset -on the ARM. Each of these example programs produce a .bin file. -kernel.img is nothing more than a .bin file, an image of the flash. -The filename is special to the raspi bootloder, so you need to use -that file name. Backup your original kernel.img if you want to go back -to playing with linux then copy the .bin file in the example to -kernel.img on the sd card. For example -cp blinker01.bin /media/9876-5432/kernel.img -sync -umount /media/9876-5432 -Insert the sd card into the raspi and power. - -It wont take you very long to figure out this is going to get painful. +what brickable means is the processor relies on a boot flash and with +that flash it is possible to change/erase it such that the processor will +not boot normally. Brickable and bricked sometimes excludes things +like jtag or speciall programming headers. From the customers perspective +a bricked board is...bricked. But on return to the vendor they may +have other equipment that is able to recover the board without doing +any soldering, perhaps plugging in jtag or some other cable on pins/pads +they have declared as reserved. Take apart a tv remote control or +calculator, etc and you may see some holes or pads on the circuit board, +for some of these devices just opening the battery case you have a view +of some of the pcboard. This is no doubt a programming header. Long +story short, so far as I know the Raspberry Pi is not brickable because +the rom/flash that performs the initial boot is for the gpu and we dont +have access to the gpu nor its boot rom/flash. The gpu relies on the +sd card to complete the boot, so the sd card flash is really the boot +flash for the system. And it is very easy for the customer to remove +and replace/modify that boot flash. So from a software perspective +unless you/we accidentally figure out how to change/erase the gpu boot +code (my guess is it is a one time programmable) you cant brick it. + +To use my samples you do not need a huge sd card. Nor do you need nor +want to download one of the linux images, takes a while to download, +takes a bigger sd card to use, and takes forever to write to the sd card. +AND I am not able to run with the firmware on those cards. I use the +firmware from http://github.com/raspberrypi. The minimum configuration +you need to get started at this level is: + +go to http://github.com/raspberrypi, you DO NOT need to download +the repo, they have some large files in there you will not need (for +my examples). go to the firmware directory and then the boot directory. +For each of these files, bootcode.bin, loader.bin, start.elf (NOT +kernel.img, dont need it, too big). Click on the file name, it will +go to another page then click on View Raw and it will let you download +the file. + +bootcode.bin is about 2MBytes, the other files are smaller, so you will +want an sd card that is at least a few meg, probably a full 128MBytes or +256MBytes or larger (gigabytes are just fine) for the gpu files plus +the sample files here. ARM memory for these samples is assumed 128MB +so they wont be even that large. + +What I do is setup the sd card with a single partition, fat32. And +copy the above files. bootcode.bin, loader.bin and start.elf. From +there you take .bin files from my examples and place them on the sd card +with the name kernel.img. It wont take you very long to figure out this +is going to get painful. 1) power off raspi 2) remove sd card @@ -79,59 +135,69 @@ There are ways to avoid this, one is jtag, which is not as expensive as it used to be. It used to be in the thousands of dollars, now it is under $50 and the software tools are free. Now the raspi does have jtag on the arm, getting the jtag connected to that is going to require -some soldering. I have not done it yet but will and will post info. -Unfortunately the connection to jtag is not there on power up you have -to run some code on the arm, so when that happens I will post that -program. - -Another method is a bootloader, typically you connect a serial port. -The program that actually boots on the processor has some way for you -to get into a bootloader. Sometimes that is all that is there, sometimes -you have to hit a key within a few seconds after it starts to boot. -The bootloader will have some way for you to use either the serial -or ethernet to copy a file into memory or flash. In this case probably -memory. I have a bootloader that works. Am working on a second one -that will probably be easier/better to use. With the bootloader method -at least how I am implementing it for the raspi, you perform the sd -card dance above one time to copy the bootloader to the sd card. You -use some flavor of serial port as described below. When the board -boots you can load your programs over the serial connection, never -needing to do the sd card dance until you want to leave your application -on the raspi and not the bootloader. The bootloader step will be -something like: +some soldering. (this is described later and in the armjtag sample). + +Another method is a bootloader, typically you use a serial port connected +to the target processor. That processor boots a bootloader program that +in some way, shape, or form allows you to interact with the bootloader +and load programs into memory (that the bootloader is not using itself) +and then the bootloader branches/jumps to your program. If your program +is still being debugged and you want to try again, you reboot the processor +the bootloader comes up and you can try again without having to move any +sd cards, etc. The sd card dance above is now replaced with the +bootloader dance: 1) power off raspi 2) power on raspi 3) type command to load and start new program - -My first bootloader is working, this will greatly save on wear and tear -on the sd card socket. You will need some sort of serial adapter. -The uart signals on the raspi are not at RS232 levels, you CANNOT -simply connect them to a "COM port", you will fry your raspberry pi. -A simple solution is to get these two items at sparkfun or something -similar (there are many ftdi usb to serial 3.3v solutions out there) +I have working bootloader examples. bootloader03 is the currently +recommended version. But you need more hardware (no soldering is +required). For those old enough to know what a serial port is, you +CANNOT connect your raspberry pi directly to this port, you will fry +the raspberry pi. You need some sort of serial port at 3.3V either +a level shifter of some sort (transceiver like a MAX232) or a usb +serial port where the signals are 3.3V (dont need to use RS232 just +stay at the logic level). The solution I recommend is a non-solder +solution: + +http://www.sparkfun.com/products/9873 +plus some male/female wire +http://www.sparkfun.com/products/9140 + +Solutions that may involve soldering http://www.sparkfun.com/products/718 http://www.sparkfun.com/products/8430 + +Or this for level shifting to a real com port. +http://www.sparkfun.com/products/449 + On the raspberry pi, the connector with two rows of a bunch of pins is P1. Starting at that corner of the board, the outside corner pin is pin 2. From pin 2 heading toward the yellow rca connector the pins are 2, 4, 6, 8, 10. Pin 6 connect to gnd on the usb to serial board -pin 8 is tx out of the raspi connect that to RX on the usb to serial -board. pin 10 is rx into the raspi, connect that to TX on the usb to +pin 8 is TX out of the raspi connect that to RX on the usb to serial +board. pin 10 is RX into the raspi, connect that to TX on the usb to serial board. Careful not to have metal items on the usb to serial board touch metal items on the raspberry pi (other than the three connections described). On your host computer you will want to use some sort of dumb terminal program, minicom, putty, etc. Set the serial port (usb to serial board) to 115200 baud, 8 data bits, no -parity, 1 stop bit. NO flow control. With minicom you likely have -to save the config, exit minicom, then restart in order for flow control -changes to take effect. - -I recommend you start with blinker01 and follow the discovery through -those to uart01, etc. If you dont have a bootloader, do the sd card -dance with the .bin file. - -bootloader01 uses the .hex file from the examples and prograspi program -bootloader02 uses the .bin file from the examples and xmodem from a -terminal program +parity, 1 stop bit. NO flow control. With minicom to get no flow +control you normally have to save the config, exit minicom, then +restart minicom and load the config in order for flow control +changes to take effect. Once you have a saved config you dont have +to mess with it any more. + +Read more about the bootloaders in their local README files. Likewise +if you are able to do some soldering on electronics see the armjtag +README file. Other than chewing up a few more GPIO pins, and another +thing you have to buy, the jtag solution is the most powerful and useful. +My typical setup is the armjtag binary as kernel.img, a usb to jtag +board like the amontec jtag-tiny and a usb to serial using minicom. + +As far as these samples go I recommend starting with blinker01 then +follow the discovery of the chip into uart01, etc. You will need some +sort of cross compiler (well maybe a native compiler on a raspberry pi +or other arm system). See the build_gcc directory if you cant get +the LITE version from codesourcery.com (now mentor graphics). diff --git a/armjtag/memmap b/armjtag/memmap index 8d9566d..9e0b82b 100644 --- a/armjtag/memmap +++ b/armjtag/memmap @@ -1,7 +1,7 @@ MEMORY { - ram : ORIGIN = 0x00000000, LENGTH = 0x1000 + ram : ORIGIN = 0x00008000, LENGTH = 0x1000 } SECTIONS diff --git a/armjtag/vectors.s b/armjtag/vectors.s index ac90378..beb9cf5 100644 --- a/armjtag/vectors.s +++ b/armjtag/vectors.s @@ -1,10 +1,7 @@ .globl _start _start: - b reset - -reset: - mov sp,#0x1000 + mov sp,#0x8000 bl notmain hang: b hang diff --git a/blinker01/README b/blinker01/README index 0fe2883..57feafa 100644 --- a/blinker01/README +++ b/blinker01/README @@ -10,9 +10,61 @@ an output. Then goes into a loop that sets the gpio, waits, resets it, waits, repeat. gpio16 is shown on the schematic to connect to the OK led. One of the bank of leds on the corner near the audio out and host usb ports. The blink rate for me is a few blinks a second perhaps. -Future examples will get use a timer if there is one and narrow in on -the clock setup, etc. -novectors.s is the entry point for this code. This just gets things -started then calls a C function (blinker01.c) where the bulk of the -program is found. +I normally set my stack pointer to be at the top of some bank of ram +if only one ram bank in the system then the top of that ram bank. See +the top level README, they force us to start somewhere other than zero +so for such simple programs like these I am setting the program to start +at 0x8000 and the stack to start at 0x7FFC. Note that on an ARM the +stack pointer (r13) points at the first address after the top of the +stack so setting r13 to 0x8000 means the stack starts at 0x7FFC and +works down away from our program. + +vectors.s is the entry point for this program, even an application on +an operating system like linux has some assembly up front before +calling the main function. For this processor the minimum is to to +set up the stack pointer and call the main function. Because some +compilers add extra stuff if they see a main() funtion I use some +function name other than main() typically for embedded systems like this. +If you dont have any pre-initialized variables, and dont assume that +un-initialized variables are zero, then you dont have or need a .data +and wont need to zero .bss. Typically the asm that preceeds the call +to the main function would prepare the .data segment if needed and zero +the .bss segment. Also the linker script is usually more complicated +to initialize global variables with the addresses and sizes of the +segments. I dont do these things so my startup code only needs to +set the stack pointer and branch to the main function. + +The example includes a Makefile that is capable of building using +gnu/gcc tools or a hybrid clang(llvm)/gnu binutils to experience an +alternate C compiler. + +The reason for the dummy function is that when a compiler optimizes +code like this: + +for(ra=0;ra<0x1000;ra++) continue; + +It replaces it with this equivalent: + +ra = 0x1000; + +Which we dont want, we want the program to actually burn some time so +we can see the led with our slow eyes. + +The compiler doesnt know what dummy does because the asm for it is not +something the C compiler can inspect. So + +for(ra=0;ra<0x1000;ra++) dummy(ra); + +To properly implement your program the C compiler must in order call +dummy(0), dummy(1), dummy(2), etc. For smaller loops it may choose +to unroll the loop. that is fine. + +Another solution is to declare ra volatile and that will cause first +the loop to not get optimized, and ra to be read from and saved to memory +each time through the loop. I like one approach you may like another. + +The program is simple refer to the broadcom arm document for information +on these registers. Remember that in the broadcom document the addresses +will be 0x7Exxxxxx not 0x20xxxxxx. + diff --git a/blinker01/memmap b/blinker01/memmap index 8d9566d..661582e 100644 --- a/blinker01/memmap +++ b/blinker01/memmap @@ -1,7 +1,7 @@ MEMORY { - ram : ORIGIN = 0x00000000, LENGTH = 0x1000 + ram : ORIGIN = 0x8000, LENGTH = 0x10000 } SECTIONS diff --git a/blinker01/vectors.s b/blinker01/vectors.s index ac90378..beb9cf5 100644 --- a/blinker01/vectors.s +++ b/blinker01/vectors.s @@ -1,10 +1,7 @@ .globl _start _start: - b reset - -reset: - mov sp,#0x1000 + mov sp,#0x8000 bl notmain hang: b hang diff --git a/blinker02/README b/blinker02/README index 3f9fc53..e20973b 100644 --- a/blinker02/README +++ b/blinker02/README @@ -6,7 +6,7 @@ these programs. There is a free-running 64 bit timer, super easy to use, just read it. -Based on a couple of experiments, without messing with anything it +Based on a couple of experiments, without messing with anything else it appears that the timer is runing at about a megahertz, 1 million ticks per second. diff --git a/blinker02/memmap b/blinker02/memmap index 8d9566d..42d3af4 100644 --- a/blinker02/memmap +++ b/blinker02/memmap @@ -1,7 +1,7 @@ MEMORY { - ram : ORIGIN = 0x00000000, LENGTH = 0x1000 + ram : ORIGIN = 0x8000, LENGTH = 0x1000 } SECTIONS diff --git a/blinker02/vectors.s b/blinker02/vectors.s index ac90378..beb9cf5 100644 --- a/blinker02/vectors.s +++ b/blinker02/vectors.s @@ -1,10 +1,7 @@ .globl _start _start: - b reset - -reset: - mov sp,#0x1000 + mov sp,#0x8000 bl notmain hang: b hang diff --git a/blinker03/README b/blinker03/README index c2cc65f..e8a64fa 100644 --- a/blinker03/README +++ b/blinker03/README @@ -5,7 +5,7 @@ on the raspberry pi. Also find information on how to load and run these programs. This example uses the free running ARM timer, not the 64 bit system -one as in blinker02 but the so called ARM timer. +timer as in blinker02 but the so called ARM timer. The system clock appears to come up at 250MHz as documented. Divide that by 250 to get 1Mhz on this free running ARM timer. Then count to four diff --git a/blinker03/memmap b/blinker03/memmap index 8d9566d..42d3af4 100644 --- a/blinker03/memmap +++ b/blinker03/memmap @@ -1,7 +1,7 @@ MEMORY { - ram : ORIGIN = 0x00000000, LENGTH = 0x1000 + ram : ORIGIN = 0x8000, LENGTH = 0x1000 } SECTIONS diff --git a/blinker03/vectors.s b/blinker03/vectors.s index ac90378..beb9cf5 100644 --- a/blinker03/vectors.s +++ b/blinker03/vectors.s @@ -1,10 +1,7 @@ .globl _start _start: - b reset - -reset: - mov sp,#0x1000 + mov sp,#0x8000 bl notmain hang: b hang diff --git a/blinker04/Makefile b/blinker04/Makefile index 4b0aa4b..665d348 100644 --- a/blinker04/Makefile +++ b/blinker04/Makefile @@ -1,7 +1,10 @@ ARMGNU ?= arm-none-eabi -COPS = -Wall -O2 -nostdlib -nostartfiles -ffreestanding +AOPS = --warn --fatal-warnings +COPS = -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding + + gcc : blinker04.hex blinker04.bin @@ -37,6 +40,7 @@ blinker04.hex : blinker04.elf + LOPS = -Wall -m32 -emit-llvm LLCOPS = -march=arm -mcpu=arm1176jzf-s LLCOPS0 = -march=arm @@ -64,7 +68,3 @@ blinker04.clang.bin : blinker04.clang.opt.elf $(ARMGNU)-objcopy blinker04.clang.opt.elf blinker04.clang.bin -O binary - - - - diff --git a/blinker04/memmap b/blinker04/memmap index 8d9566d..42d3af4 100644 --- a/blinker04/memmap +++ b/blinker04/memmap @@ -1,7 +1,7 @@ MEMORY { - ram : ORIGIN = 0x00000000, LENGTH = 0x1000 + ram : ORIGIN = 0x8000, LENGTH = 0x1000 } SECTIONS diff --git a/blinker04/vectors.s b/blinker04/vectors.s index ac90378..beb9cf5 100644 --- a/blinker04/vectors.s +++ b/blinker04/vectors.s @@ -1,10 +1,7 @@ .globl _start _start: - b reset - -reset: - mov sp,#0x1000 + mov sp,#0x8000 bl notmain hang: b hang diff --git a/bootloader02/bootloader02.c b/bootloader02/bootloader02.c index a6eb816..a01d092 100644 --- a/bootloader02/bootloader02.c +++ b/bootloader02/bootloader02.c @@ -2,6 +2,14 @@ //------------------------------------------------------------------------- //------------------------------------------------------------------------- +//The raspberry pi wants you to not have your kernel.img file loaded +//at address 0x0000. Using a bootloader like this it works just fine +//but to avoid having example binaries that are at 0x8000 for running +//from the sd card and a binary at 0x0000 for loading with the +//bootloader, instead the bootloader is going to default to 0x8000 +//as well. +#define ARMBASE 0x8000 + extern void PUT32 ( unsigned int, unsigned int ); extern void PUT16 ( unsigned int, unsigned int ); extern void PUT8 ( unsigned int, unsigned int ); @@ -147,7 +155,7 @@ int notmain ( void ) if(GET32(AUX_MU_LSR_REG)&0x01) break; } block=1; - addr=0; + addr=ARMBASE; while(1) { xstring[0]=uart_recv(); @@ -184,7 +192,7 @@ int notmain ( void ) } if(xstring[0]==0x04) { - BRANCHTO(0); + BRANCHTO(ARMBASE); } return(0); } diff --git a/bootloader03/Makefile b/bootloader03/Makefile index 647aab1..cf42c49 100644 --- a/bootloader03/Makefile +++ b/bootloader03/Makefile @@ -15,7 +15,7 @@ clean : rm -f *.list rm -f *.img rm -f *.bc - rm -f *.clang.opt.s + rm -f *.clang.s vectors.o : vectors.s @@ -24,14 +24,19 @@ vectors.o : vectors.s bootloader03.o : bootloader03.c $(ARMGNU)-gcc $(COPS) -c bootloader03.c -o bootloader03.o -kernel.img : loader vectors.o bootloader03.o - $(ARMGNU)-ld vectors.o bootloader03.o -T loader -o bootloader03.elf +periph.o : periph.c + $(ARMGNU)-gcc $(COPS) -c periph.c -o periph.o + +kernel.img : loader vectors.o periph.o bootloader03.o + $(ARMGNU)-ld vectors.o periph.o bootloader03.o -T loader -o bootloader03.elf $(ARMGNU)-objdump -D bootloader03.elf > bootloader03.list $(ARMGNU)-objcopy bootloader03.elf -O ihex bootloader03.hex $(ARMGNU)-objcopy bootloader03.elf -O binary kernel.img + + start.o : start.s $(ARMGNU)-as start.s -o start.o @@ -50,34 +55,29 @@ blinker.bin : memmap start.o blinker.o LOPS = -Wall -m32 -emit-llvm -LLCOPS = -march=arm -mcpu=arm1176jzf-s LLCOPS0 = -march=arm LLCOPS1 = -march=arm -mcpu=arm1176jzf-s +LLCOPS = $(LLCOPS1) COPS = -Wall -O2 -nostdlib -nostartfiles -ffreestanding OOPS = -std-compile-opts -clang : bootloader03.clang.hex bootloader03.clang.bin - - -bootloader03.clang.bc : bootloader03.c - clang $(LOPS) -c bootloader03.c -o bootloader03.clang.bc - -bootloader03.clang.opt.elf : loader vectors.o bootloader03.clang.bc - opt $(OOPS) bootloader03.clang.bc -o bootloader03.clang.opt.bc - llc $(LLCOPS) bootloader03.clang.opt.bc -o bootloader03.clang.opt.s - $(ARMGNU)-as bootloader03.clang.opt.s -o bootloader03.clang.opt.o - $(ARMGNU)-ld -o bootloader03.clang.opt.elf -T loader vectors.o bootloader03.clang.opt.o - $(ARMGNU)-objdump -D bootloader03.clang.opt.elf > bootloader03.clang.opt.list - -bootloader03.clang.hex : bootloader03.clang.opt.elf - $(ARMGNU)-objcopy bootloader03.clang.opt.elf bootloader03.clang.hex -O ihex - -bootloader03.clang.bin : bootloader03.clang.opt.elf - $(ARMGNU)-objcopy bootloader03.clang.opt.elf bootloader03.clang.bin -O binary - +clang : bootloader03.bin +bootloader03.bc : bootloader03.c + clang $(LOPS) -c bootloader03.c -o bootloader03.bc +periph.bc : periph.c + clang $(LOPS) -c periph.c -o periph.bc +bootloader03.clang.elf : loader vectors.o bootloader03.bc periph.bc + llvm-link periph.bc bootloader03.bc -o bootloader03.nopt.bc + opt $(OOPS) bootloader03.nopt.bc -o bootloader03.opt.bc + llc $(LLCOPS) bootloader03.opt.bc -o bootloader03.clang.s + $(ARMGNU)-as bootloader03.clang.s -o bootloader03.clang.o + $(ARMGNU)-ld -o bootloader03.clang.elf -T loader vectors.o bootloader03.clang.o + $(ARMGNU)-objdump -D bootloader03.clang.elf > bootloader03.clang.list +bootloader03.bin : bootloader03.clang.elf + $(ARMGNU)-objcopy bootloader03.clang.elf bootloader03.clang.bin -O binary diff --git a/bootloader03/README b/bootloader03/README index adb4701..c43fa27 100644 --- a/bootloader03/README +++ b/bootloader03/README @@ -1,21 +1,20 @@ -See the top level README for information on where to find the -schematic and programmers reference manual for the ARM processor -on the raspberry pi. Also find information on how to load and run -these programs. +See the top level README file for more information on documentation +and how to run these programs. Derived from bootloader02, this is a very simple bootloader. Instead of the sd dance (see toplevel README), this makes life a bit simpler and greatly reduces physical wear and tear on the sd card socket. Do the sd card dance one time with kernel.img. Get some sort of serial -solution to connect a dumb termial program (minicom, hyperterm, etc) -with xmodem capabilities to the uart on the raspberry pi. (see toplevel -README) +solution to connect a dumb termial program with xmodem capabilities +to the uart on the raspberry pi. (see the toplevel README for more +information). The difference between bootloader02 and bootloader03 is that this one uses a state machine for xmodem, maybe it will recover from a lost byte -if there is ever one. You take the .bin file of your test program, -assumed to be built based on address 0 and less than 0x200000 bytes. +if there is ever one, maybe not. You take the .bin file of your test +program, assumed to be built based on address 0x8000 and less than +0x200000-0x8000 bytes in size. With uart connected to a terminal 1) power off raspberry pi 2) power on raspberry pi @@ -26,7 +25,10 @@ This bootloader sits at 0x200000 so that you have 0x200000 bytes to develop with. And that way if you like your program you can just copy a .bin version to kernel.img on the sd card and use it. Fairly easy to change this address. bootloader03.c and vectors.s each have -a copy of this value. +a copy of this value. bootloader04 will use a rasberry pi specific +config file to move much deeper in memory giving you much more room +if you want more room use that bootloader. bootloader01 uses .hex files, bootloader02 and bootloader03 use .bin -files, .hex files wont work. +files, .hex files wont work. Consider bootloader01 and 02 to be +obsolete. diff --git a/bootloader03/bootloader03.c b/bootloader03/bootloader03.c index 687e1b7..6c9c0a7 100644 --- a/bootloader03/bootloader03.c +++ b/bootloader03/bootloader03.c @@ -2,80 +2,34 @@ //------------------------------------------------------------------------- //------------------------------------------------------------------------- +//The raspberry pi wants you to not have your kernel.img file loaded +//at address 0x0000. Using a bootloader like this it works just fine +//but to avoid having example binaries that are at 0x8000 for running +//from the sd card and a binary at 0x0000 for loading with the +//bootloader, instead the bootloader is going to default to 0x8000 +//as well. +#define ARMBASE 0x8000 + extern void PUT32 ( unsigned int, unsigned int ); extern void PUT16 ( unsigned int, unsigned int ); extern void PUT8 ( unsigned int, unsigned int ); extern unsigned int GET32 ( unsigned int ); +extern unsigned int GETPC ( void ); extern void BRANCHTO ( unsigned int ); extern void dummy ( unsigned int ); -#define ARM_TIMER_CTL 0x2000B408 -#define ARM_TIMER_CNT 0x2000B420 - -#define GPFSEL1 0x20200004 -#define GPSET0 0x2020001C -#define GPCLR0 0x20200028 -#define GPPUD 0x20200094 -#define GPPUDCLK0 0x20200098 +extern void uart_init ( void ); +extern unsigned int uart_lcr ( void ); +extern void uart_send ( unsigned int ); +extern unsigned int uart_recv ( void ); +extern void hexstring ( unsigned int ); +extern void hexstrings ( unsigned int ); +extern void timer_init ( void ); +extern unsigned int timer_tick ( void ); -#define AUX_ENABLES 0x20215004 -#define AUX_MU_IO_REG 0x20215040 -#define AUX_MU_IER_REG 0x20215044 -#define AUX_MU_IIR_REG 0x20215048 -#define AUX_MU_LCR_REG 0x2021504C -#define AUX_MU_MCR_REG 0x20215050 -#define AUX_MU_LSR_REG 0x20215054 -#define AUX_MU_MSR_REG 0x20215058 -#define AUX_MU_SCRATCH 0x2021505C -#define AUX_MU_CNTL_REG 0x20215060 -#define AUX_MU_STAT_REG 0x20215064 -#define AUX_MU_BAUD_REG 0x20215068 - -//GPIO14 TXD0 and TXD1 -//GPIO15 RXD0 and RXD1 -//------------------------------------------------------------------------ -unsigned int uart_recv ( void ) -{ - while(1) - { - if(GET32(AUX_MU_LSR_REG)&0x01) break; - } - return(GET32(AUX_MU_IO_REG)&0xFF); -} -//------------------------------------------------------------------------ -void uart_send ( unsigned int c ) -{ - while(1) - { - if(GET32(AUX_MU_LSR_REG)&0x20) break; - } - PUT32(AUX_MU_IO_REG,c); -} -//------------------------------------------------------------------------ -void hexstrings ( unsigned int d ) -{ - //unsigned int ra; - unsigned int rb; - unsigned int rc; +extern void timer_init ( void ); +extern unsigned int timer_tick ( void ); - rb=32; - while(1) - { - rb-=4; - rc=(d>>rb)&0xF; - if(rc>9) rc+=0x37; else rc+=0x30; - uart_send(rc); - if(rb==0) break; - } - uart_send(0x20); -} -//------------------------------------------------------------------------ -void hexstring ( unsigned int d ) -{ - hexstrings(d); - uart_send(0x0D); - uart_send(0x0A); -} //------------------------------------------------------------------------ unsigned char xstring[256]; //------------------------------------------------------------------------ @@ -90,31 +44,10 @@ int notmain ( void ) unsigned int crc; - PUT32(AUX_ENABLES,1); - PUT32(AUX_MU_IER_REG,0); - PUT32(AUX_MU_CNTL_REG,0); - PUT32(AUX_MU_LCR_REG,3); - PUT32(AUX_MU_MCR_REG,0); - PUT32(AUX_MU_IER_REG,0); - PUT32(AUX_MU_IIR_REG,0xC6); - PUT32(AUX_MU_BAUD_REG,270); - ra=GET32(GPFSEL1); - ra&=~(7<<12); //gpio14 - ra|=2<<12; //alt5 - ra&=~(7<<15); //gpio15 - ra|=2<<15; //alt5 - PUT32(GPFSEL1,ra); - PUT32(GPPUD,0); - for(ra=0;ra<150;ra++) dummy(ra); - PUT32(GPPUDCLK0,(1<<14)|(1<<15)); - for(ra=0;ra<150;ra++) dummy(ra); - PUT32(GPPUDCLK0,0); - PUT32(AUX_MU_CNTL_REG,3); - - PUT32(ARM_TIMER_CTL,0x00F90000); - PUT32(ARM_TIMER_CTL,0x00F90200); - + uart_init(); hexstring(0x12345678); + hexstring(GETPC()); + timer_init(); //SOH 0x01 //ACK 0x06 @@ -132,26 +65,27 @@ int notmain ( void ) //a single EOT instead of SOH when done, send an ACK on it too block=1; - addr=0; + addr=ARMBASE; state=0; - rx=GET32(ARM_TIMER_CNT); + crc=0; + rx=timer_tick(); while(1) { - ra=GET32(ARM_TIMER_CNT); + ra=timer_tick(); if((ra-rx)>=4000000) { uart_send(0x15); rx+=4000000; } - if((GET32(AUX_MU_LSR_REG)&0x01)==0) continue; - xstring[state]=GET32(AUX_MU_IO_REG)&0xFF; - rx=GET32(ARM_TIMER_CNT); + if((uart_lcr()&0x01)==0) continue; + xstring[state]=uart_recv(); + rx=timer_tick(); if(state==0) { if(xstring[state]==0x04) { uart_send(0x06); - BRANCHTO(0); + BRANCHTO(ARMBASE); break; } } diff --git a/bootloader03/kernel.img b/bootloader03/kernel.img index 05acf78..e207acf 100755 Binary files a/bootloader03/kernel.img and b/bootloader03/kernel.img differ diff --git a/bootloader03/loader b/bootloader03/loader index 7bb7988..dce5594 100644 --- a/bootloader03/loader +++ b/bootloader03/loader @@ -1,7 +1,7 @@ MEMORY { - ram : ORIGIN = 0x00000000, LENGTH = 0x10000000 + ram : ORIGIN = 0x8000, LENGTH = 0x1000000 } SECTIONS diff --git a/bootloader03/memmap b/bootloader03/memmap index 203c50d..42d3af4 100644 --- a/bootloader03/memmap +++ b/bootloader03/memmap @@ -1,7 +1,7 @@ MEMORY { - ram : ORIGIN = 0x00000000, LENGTH = 0x200000 + ram : ORIGIN = 0x8000, LENGTH = 0x1000 } SECTIONS diff --git a/bootloader03/periph.c b/bootloader03/periph.c new file mode 100644 index 0000000..332da06 --- /dev/null +++ b/bootloader03/periph.c @@ -0,0 +1,124 @@ + +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- + +extern void PUT32 ( unsigned int, unsigned int ); +extern void PUT16 ( unsigned int, unsigned int ); +extern void PUT8 ( unsigned int, unsigned int ); +extern unsigned int GET32 ( unsigned int ); +extern void BRANCHTO ( unsigned int ); +extern void dummy ( unsigned int ); + +#define ARM_TIMER_CTL 0x2000B408 +#define ARM_TIMER_CNT 0x2000B420 + +#define GPFSEL1 0x20200004 +#define GPSET0 0x2020001C +#define GPCLR0 0x20200028 +#define GPPUD 0x20200094 +#define GPPUDCLK0 0x20200098 + +#define AUX_ENABLES 0x20215004 +#define AUX_MU_IO_REG 0x20215040 +#define AUX_MU_IER_REG 0x20215044 +#define AUX_MU_IIR_REG 0x20215048 +#define AUX_MU_LCR_REG 0x2021504C +#define AUX_MU_MCR_REG 0x20215050 +#define AUX_MU_LSR_REG 0x20215054 +#define AUX_MU_MSR_REG 0x20215058 +#define AUX_MU_SCRATCH 0x2021505C +#define AUX_MU_CNTL_REG 0x20215060 +#define AUX_MU_STAT_REG 0x20215064 +#define AUX_MU_BAUD_REG 0x20215068 + +//GPIO14 TXD0 and TXD1 +//GPIO15 RXD0 and RXD1 +//------------------------------------------------------------------------ +unsigned int uart_lcr ( void ) +{ + return(GET32(AUX_MU_LSR_REG)); +} +//------------------------------------------------------------------------ +unsigned int uart_recv ( void ) +{ + while(1) + { + if(GET32(AUX_MU_LSR_REG)&0x01) break; + } + return(GET32(AUX_MU_IO_REG)&0xFF); +} +//------------------------------------------------------------------------ +void uart_send ( unsigned int c ) +{ + while(1) + { + if(GET32(AUX_MU_LSR_REG)&0x20) break; + } + PUT32(AUX_MU_IO_REG,c); +} +//------------------------------------------------------------------------ +void hexstrings ( unsigned int d ) +{ + //unsigned int ra; + unsigned int rb; + unsigned int rc; + + rb=32; + while(1) + { + rb-=4; + rc=(d>>rb)&0xF; + if(rc>9) rc+=0x37; else rc+=0x30; + uart_send(rc); + if(rb==0) break; + } + uart_send(0x20); +} +//------------------------------------------------------------------------ +void hexstring ( unsigned int d ) +{ + hexstrings(d); + uart_send(0x0D); + uart_send(0x0A); +} +//------------------------------------------------------------------------ +void uart_init ( void ) +{ + unsigned int ra; + + PUT32(AUX_ENABLES,1); + PUT32(AUX_MU_IER_REG,0); + PUT32(AUX_MU_CNTL_REG,0); + PUT32(AUX_MU_LCR_REG,3); + PUT32(AUX_MU_MCR_REG,0); + PUT32(AUX_MU_IER_REG,0); + PUT32(AUX_MU_IIR_REG,0xC6); + PUT32(AUX_MU_BAUD_REG,270); + ra=GET32(GPFSEL1); + ra&=~(7<<12); //gpio14 + ra|=2<<12; //alt5 + ra&=~(7<<15); //gpio15 + ra|=2<<15; //alt5 + PUT32(GPFSEL1,ra); + PUT32(GPPUD,0); + for(ra=0;ra<150;ra++) dummy(ra); + PUT32(GPPUDCLK0,(1<<14)|(1<<15)); + for(ra=0;ra<150;ra++) dummy(ra); + PUT32(GPPUDCLK0,0); + PUT32(AUX_MU_CNTL_REG,3); +} +//------------------------------------------------------------------------ +void timer_init ( void ) +{ + //0xF9+1 = 250 + //250MHz/250 = 1MHz + PUT32(ARM_TIMER_CTL,0x00F90000); + PUT32(ARM_TIMER_CTL,0x00F90200); +} +//------------------------------------------------------------------------- +unsigned int timer_tick ( void ) +{ + return(GET32(ARM_TIMER_CNT)); +} +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- diff --git a/bootloader03/start.s b/bootloader03/start.s index 07817bc..beb9cf5 100644 --- a/bootloader03/start.s +++ b/bootloader03/start.s @@ -1,6 +1,7 @@ .globl _start _start: + mov sp,#0x8000 bl notmain hang: b hang diff --git a/bootloader03/vectors.s b/bootloader03/vectors.s index 484cc85..b305ba6 100644 --- a/bootloader03/vectors.s +++ b/bootloader03/vectors.s @@ -1,12 +1,12 @@ .globl _start _start: - b reset + b skip -.space 0x200000-4,0 +.space 0x200000-0x8004,0 -reset: - mov sp,#0x10000000 +skip: + mov sp,#0x08000000 bl notmain hang: b hang @@ -30,6 +30,11 @@ GET32: ldr r0,[r0] bx lr +.globl GETPC +GETPC: + mov r0,lr + bx lr + .globl BRANCHTO BRANCHTO: bx r0 diff --git a/bootloader04/Makefile b/bootloader04/Makefile new file mode 100644 index 0000000..c35c3d9 --- /dev/null +++ b/bootloader04/Makefile @@ -0,0 +1,83 @@ + +ARMGNU ?= arm-none-eabi + +COPS = -Wall -O2 -nostdlib -nostartfiles -ffreestanding + +gcc : kernel.img blinker.bin + +all : gcc clang + +clean : + rm -f *.o + rm -f *.bin + rm -f *.hex + rm -f *.elf + rm -f *.list + rm -f *.img + rm -f *.bc + rm -f *.clang.s + + +vectors.o : vectors.s + $(ARMGNU)-as vectors.s -o vectors.o + +bootloader04.o : bootloader04.c + $(ARMGNU)-gcc $(COPS) -c bootloader04.c -o bootloader04.o + +periph.o : periph.c + $(ARMGNU)-gcc $(COPS) -c periph.c -o periph.o + +kernel.img : loader vectors.o periph.o bootloader04.o + $(ARMGNU)-ld vectors.o periph.o bootloader04.o -T loader -o bootloader04.elf + $(ARMGNU)-objdump -D bootloader04.elf > bootloader04.list + $(ARMGNU)-objcopy bootloader04.elf -O ihex bootloader04.hex + $(ARMGNU)-objcopy bootloader04.elf -O binary kernel.img + + + + + +start.o : start.s + $(ARMGNU)-as start.s -o start.o + +blinker.o : blinker.c + $(ARMGNU)-gcc $(COPS) -c blinker.c -o blinker.o + +blinker.bin : memmap start.o blinker.o + $(ARMGNU)-ld start.o blinker.o -T memmap -o blinker.elf + $(ARMGNU)-objdump -D blinker.elf > blinker.list + $(ARMGNU)-objcopy blinker.elf -O ihex blinker.hex + $(ARMGNU)-objcopy blinker.elf -O binary blinker.bin + + + + + + +LOPS = -Wall -m32 -emit-llvm +LLCOPS0 = -march=arm +LLCOPS1 = -march=arm -mcpu=arm1176jzf-s +LLCOPS = $(LLCOPS1) +COPS = -Wall -O2 -nostdlib -nostartfiles -ffreestanding +OOPS = -std-compile-opts + +clang : bootloader04.bin + +bootloader04.bc : bootloader04.c + clang $(LOPS) -c bootloader04.c -o bootloader04.bc + +periph.bc : periph.c + clang $(LOPS) -c periph.c -o periph.bc + +bootloader04.clang.elf : loader vectors.o bootloader04.bc periph.bc + llvm-link periph.bc bootloader04.bc -o bootloader04.nopt.bc + opt $(OOPS) bootloader04.nopt.bc -o bootloader04.opt.bc + llc $(LLCOPS) bootloader04.opt.bc -o bootloader04.clang.s + $(ARMGNU)-as bootloader04.clang.s -o bootloader04.clang.o + $(ARMGNU)-ld -o bootloader04.clang.elf -T loader vectors.o bootloader04.clang.o + $(ARMGNU)-objdump -D bootloader04.clang.elf > bootloader04.clang.list + +bootloader04.bin : bootloader04.clang.elf + $(ARMGNU)-objcopy bootloader04.clang.elf bootloader04.clang.bin -O binary + + diff --git a/bootloader04/README b/bootloader04/README new file mode 100644 index 0000000..05f4f86 --- /dev/null +++ b/bootloader04/README @@ -0,0 +1,9 @@ + +Same as bootloader03, except it uses the config.txt file to load to +0x06000000 leaving much more room (than you would probably want to +use xmodem to load) for development. + +Copy both kernel.img and config.txt to the sd card. Remove or modify +config.txt when you change to some other kernel.img. The main drawback +to this version is remembering to copy and then remove/replace both +files. diff --git a/bootloader04/blinker.c b/bootloader04/blinker.c new file mode 100644 index 0000000..2e6388d --- /dev/null +++ b/bootloader04/blinker.c @@ -0,0 +1,57 @@ + +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- + +extern void PUT32 ( unsigned int, unsigned int ); +extern unsigned int GET32 ( unsigned int ); +extern void dummy ( unsigned int ); + +#define ARM_TIMER_LOD 0x2000B400 +#define ARM_TIMER_VAL 0x2000B404 +#define ARM_TIMER_CTL 0x2000B408 +#define ARM_TIMER_DIV 0x2000B41C +#define ARM_TIMER_CNT 0x2000B420 + +#define SYSTIMERCLO 0x20003004 +#define GPFSEL1 0x20200004 +#define GPSET0 0x2020001C +#define GPCLR0 0x20200028 + +#define TIMEOUT 1000000 + +//------------------------------------------------------------------------- +int notmain ( void ) +{ + unsigned int ra; + unsigned int rb; + + ra=GET32(GPFSEL1); + ra&=~(7<<18); + ra|=1<<18; + PUT32(GPFSEL1,ra); + + PUT32(ARM_TIMER_CTL,0x00F90000); + PUT32(ARM_TIMER_CTL,0x00F90200); + + rb=GET32(ARM_TIMER_CNT); + while(1) + { + PUT32(GPSET0,1<<16); + while(1) + { + ra=GET32(ARM_TIMER_CNT); + if((ra-rb)>=TIMEOUT) break; + } + rb+=TIMEOUT; + PUT32(GPCLR0,1<<16); + while(1) + { + ra=GET32(ARM_TIMER_CNT); + if((ra-rb)>=TIMEOUT) break; + } + rb+=TIMEOUT; + } + return(0); +} +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- diff --git a/bootloader04/bootloader04.c b/bootloader04/bootloader04.c new file mode 100644 index 0000000..6c9c0a7 --- /dev/null +++ b/bootloader04/bootloader04.c @@ -0,0 +1,166 @@ + +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- + +//The raspberry pi wants you to not have your kernel.img file loaded +//at address 0x0000. Using a bootloader like this it works just fine +//but to avoid having example binaries that are at 0x8000 for running +//from the sd card and a binary at 0x0000 for loading with the +//bootloader, instead the bootloader is going to default to 0x8000 +//as well. +#define ARMBASE 0x8000 + +extern void PUT32 ( unsigned int, unsigned int ); +extern void PUT16 ( unsigned int, unsigned int ); +extern void PUT8 ( unsigned int, unsigned int ); +extern unsigned int GET32 ( unsigned int ); +extern unsigned int GETPC ( void ); +extern void BRANCHTO ( unsigned int ); +extern void dummy ( unsigned int ); + +extern void uart_init ( void ); +extern unsigned int uart_lcr ( void ); +extern void uart_send ( unsigned int ); +extern unsigned int uart_recv ( void ); +extern void hexstring ( unsigned int ); +extern void hexstrings ( unsigned int ); +extern void timer_init ( void ); +extern unsigned int timer_tick ( void ); + +extern void timer_init ( void ); +extern unsigned int timer_tick ( void ); + +//------------------------------------------------------------------------ +unsigned char xstring[256]; +//------------------------------------------------------------------------ +int notmain ( void ) +{ + unsigned int ra; + //unsigned int rb; + unsigned int rx; + unsigned int addr; + unsigned int block; + unsigned int state; + + unsigned int crc; + + uart_init(); + hexstring(0x12345678); + hexstring(GETPC()); + timer_init(); + +//SOH 0x01 +//ACK 0x06 +//NAK 0x15 +//EOT 0x04 + +//block numbers start with 1 + +//132 byte packet +//starts with SOH +//block number byte +//255-block number +//128 bytes of data +//checksum byte (whole packet) +//a single EOT instead of SOH when done, send an ACK on it too + + block=1; + addr=ARMBASE; + state=0; + crc=0; + rx=timer_tick(); + while(1) + { + ra=timer_tick(); + if((ra-rx)>=4000000) + { + uart_send(0x15); + rx+=4000000; + } + if((uart_lcr()&0x01)==0) continue; + xstring[state]=uart_recv(); + rx=timer_tick(); + if(state==0) + { + if(xstring[state]==0x04) + { + uart_send(0x06); + BRANCHTO(ARMBASE); + break; + } + } + switch(state) + { + case 0: + { + if(xstring[state]==0x01) + { + crc=xstring[state]; + state++; + } + else + { + //state=0; + uart_send(0x15); + } + break; + } + case 1: + { + if(xstring[state]==block) + { + crc+=xstring[state]; + state++; + } + else + { + state=0; + uart_send(0x15); + } + break; + } + case 2: + { + if(xstring[state]==(0xFF-xstring[state-1])) + { + crc+=xstring[state]; + state++; + } + else + { + uart_send(0x15); + state=0; + } + break; + } + case 131: + { + crc&=0xFF; + if(xstring[state]==crc) + { + for(ra=0;ra<128;ra++) + { + PUT8(addr++,xstring[ra+3]); + } + uart_send(0x06); + block=(block+1)&0xFF; + } + else + { + uart_send(0x15); + } + state=0; + break; + } + default: + { + crc+=xstring[state]; + state++; + break; + } + } + } + return(0); +} +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- diff --git a/bootloader04/config.txt b/bootloader04/config.txt new file mode 100644 index 0000000..8f3898d --- /dev/null +++ b/bootloader04/config.txt @@ -0,0 +1 @@ +kernel_address=0x06000000 diff --git a/bootloader04/kernel.img b/bootloader04/kernel.img new file mode 100755 index 0000000..123f5f5 Binary files /dev/null and b/bootloader04/kernel.img differ diff --git a/bootloader04/loader b/bootloader04/loader new file mode 100644 index 0000000..616575e --- /dev/null +++ b/bootloader04/loader @@ -0,0 +1,12 @@ + +MEMORY +{ + ram : ORIGIN = 0x06000000, LENGTH = 0x2000 +} + +SECTIONS +{ + .text : { *(.text*) } > ram + .bss : { *(.bss*) } > ram +} + diff --git a/bootloader04/memmap b/bootloader04/memmap new file mode 100644 index 0000000..42d3af4 --- /dev/null +++ b/bootloader04/memmap @@ -0,0 +1,12 @@ + +MEMORY +{ + ram : ORIGIN = 0x8000, LENGTH = 0x1000 +} + +SECTIONS +{ + .text : { *(.text*) } > ram + .bss : { *(.bss*) } > ram +} + diff --git a/bootloader04/periph.c b/bootloader04/periph.c new file mode 100644 index 0000000..332da06 --- /dev/null +++ b/bootloader04/periph.c @@ -0,0 +1,124 @@ + +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- + +extern void PUT32 ( unsigned int, unsigned int ); +extern void PUT16 ( unsigned int, unsigned int ); +extern void PUT8 ( unsigned int, unsigned int ); +extern unsigned int GET32 ( unsigned int ); +extern void BRANCHTO ( unsigned int ); +extern void dummy ( unsigned int ); + +#define ARM_TIMER_CTL 0x2000B408 +#define ARM_TIMER_CNT 0x2000B420 + +#define GPFSEL1 0x20200004 +#define GPSET0 0x2020001C +#define GPCLR0 0x20200028 +#define GPPUD 0x20200094 +#define GPPUDCLK0 0x20200098 + +#define AUX_ENABLES 0x20215004 +#define AUX_MU_IO_REG 0x20215040 +#define AUX_MU_IER_REG 0x20215044 +#define AUX_MU_IIR_REG 0x20215048 +#define AUX_MU_LCR_REG 0x2021504C +#define AUX_MU_MCR_REG 0x20215050 +#define AUX_MU_LSR_REG 0x20215054 +#define AUX_MU_MSR_REG 0x20215058 +#define AUX_MU_SCRATCH 0x2021505C +#define AUX_MU_CNTL_REG 0x20215060 +#define AUX_MU_STAT_REG 0x20215064 +#define AUX_MU_BAUD_REG 0x20215068 + +//GPIO14 TXD0 and TXD1 +//GPIO15 RXD0 and RXD1 +//------------------------------------------------------------------------ +unsigned int uart_lcr ( void ) +{ + return(GET32(AUX_MU_LSR_REG)); +} +//------------------------------------------------------------------------ +unsigned int uart_recv ( void ) +{ + while(1) + { + if(GET32(AUX_MU_LSR_REG)&0x01) break; + } + return(GET32(AUX_MU_IO_REG)&0xFF); +} +//------------------------------------------------------------------------ +void uart_send ( unsigned int c ) +{ + while(1) + { + if(GET32(AUX_MU_LSR_REG)&0x20) break; + } + PUT32(AUX_MU_IO_REG,c); +} +//------------------------------------------------------------------------ +void hexstrings ( unsigned int d ) +{ + //unsigned int ra; + unsigned int rb; + unsigned int rc; + + rb=32; + while(1) + { + rb-=4; + rc=(d>>rb)&0xF; + if(rc>9) rc+=0x37; else rc+=0x30; + uart_send(rc); + if(rb==0) break; + } + uart_send(0x20); +} +//------------------------------------------------------------------------ +void hexstring ( unsigned int d ) +{ + hexstrings(d); + uart_send(0x0D); + uart_send(0x0A); +} +//------------------------------------------------------------------------ +void uart_init ( void ) +{ + unsigned int ra; + + PUT32(AUX_ENABLES,1); + PUT32(AUX_MU_IER_REG,0); + PUT32(AUX_MU_CNTL_REG,0); + PUT32(AUX_MU_LCR_REG,3); + PUT32(AUX_MU_MCR_REG,0); + PUT32(AUX_MU_IER_REG,0); + PUT32(AUX_MU_IIR_REG,0xC6); + PUT32(AUX_MU_BAUD_REG,270); + ra=GET32(GPFSEL1); + ra&=~(7<<12); //gpio14 + ra|=2<<12; //alt5 + ra&=~(7<<15); //gpio15 + ra|=2<<15; //alt5 + PUT32(GPFSEL1,ra); + PUT32(GPPUD,0); + for(ra=0;ra<150;ra++) dummy(ra); + PUT32(GPPUDCLK0,(1<<14)|(1<<15)); + for(ra=0;ra<150;ra++) dummy(ra); + PUT32(GPPUDCLK0,0); + PUT32(AUX_MU_CNTL_REG,3); +} +//------------------------------------------------------------------------ +void timer_init ( void ) +{ + //0xF9+1 = 250 + //250MHz/250 = 1MHz + PUT32(ARM_TIMER_CTL,0x00F90000); + PUT32(ARM_TIMER_CTL,0x00F90200); +} +//------------------------------------------------------------------------- +unsigned int timer_tick ( void ) +{ + return(GET32(ARM_TIMER_CNT)); +} +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- diff --git a/bootloader04/start.s b/bootloader04/start.s new file mode 100644 index 0000000..beb9cf5 --- /dev/null +++ b/bootloader04/start.s @@ -0,0 +1,20 @@ + +.globl _start +_start: + mov sp,#0x8000 + bl notmain +hang: b hang + +.globl PUT32 +PUT32: + str r1,[r0] + bx lr + +.globl GET32 +GET32: + ldr r0,[r0] + bx lr + +.globl dummy +dummy: + bx lr diff --git a/bootloader04/vectors.s b/bootloader04/vectors.s new file mode 100644 index 0000000..8a2caa3 --- /dev/null +++ b/bootloader04/vectors.s @@ -0,0 +1,40 @@ + +.globl _start +_start: + mov sp,#0x08000000 + bl notmain +hang: b hang + +.globl PUT32 +PUT32: + str r1,[r0] + bx lr + +.globl PUT16 +PUT16: + strh r1,[r0] + bx lr + +.globl PUT8 +PUT8: + strb r1,[r0] + bx lr + +.globl GET32 +GET32: + ldr r0,[r0] + bx lr + +.globl GETPC +GETPC: + mov r0,lr + bx lr + +.globl BRANCHTO +BRANCHTO: + bx r0 + +.globl dummy +dummy: + bx lr +