projects:avrada
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revision | |||
projects:avrada [2012/08/05 10:52] – mkucia | projects:avrada [2012/08/05 11:02] (current) – [Device specyfication package] mkucia | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Programming AVR with ADA programming language ====== | ||
+ | |||
+ | The purpose of this page is to provide information on building and running embedded software on [[http:// | ||
+ | |||
+ | January 2012 | ||
+ | |||
+ | ===== Software ===== | ||
+ | To start writing embedded code in Ada, several software packages are required: | ||
+ | * [[http:// | ||
+ | * AdaCore GPS (part of GNAT AVR package) | ||
+ | * [[http:// | ||
+ | * [[http:// | ||
+ | |||
+ | ===== CRT - C Run-Time Library ===== | ||
+ | Usually programs written in Ada comes with extensive run-time library. In embedded environment especially such low-end as in AVR8 platform, memory cost of such RTL is very high. Additionally there' | ||
+ | * Program entry point | ||
+ | * Vector table | ||
+ | * Stack initialization | ||
+ | * Global variables initialization | ||
+ | AdaCore provides sample initialization code written in assembler for ATmega2560. Instead of writing code for other chips it is easier (and safer) to use CRT code from WinAvr. Compiled CRT files can be found in '' | ||
+ | |||
+ | ===== Device specyfication package ===== | ||
+ | Each AVR device has a number of internal peripherals and registers associated with them. Registers are located at various memory locations specific to the type of the device. AdaCore provides tool (avr_gen) for generating Ada package based on Atmel XML device specification files, but only in redundant AVRStudio 4 format. I rewritten similar tool which works with current device specification format (AVRStudio 5). Please note that tool is designed to work with AVR8 device description files (using it with AVR32 and Xmega families will require modifications). | ||
+ | |||
+ | * [[: | ||
+ | * {{: | ||
+ | * [[: | ||
+ | * [[: | ||
+ | |||
+ | To build this tool following software is required: | ||
+ | |||
+ | * GNAT x86 (for your OS) | ||
+ | * XMLAda (Both software packages are available on [[http:// | ||
+ | |||
+ | To build device specification package: | ||
+ | - Build or unzip tool | ||
+ | - Copy device specification file from ''< | ||
+ | - Run '' | ||
+ | ===== Makefile ===== | ||
+ | When all required files and tools are installed, machine code can be compiled using '' | ||
+ | |||
+ | Sample makefile for AtMega8 is: | ||
+ | |||
+ | < | ||
+ | |||
+ | program: | ||
+ | avrdude -pm8 < | ||
+ | |||
+ | main.elf: force | ||
+ | avr-gnatmake main -o $@ -Os -mmcu=avr4 --RTS=zfp -largs crtm8._o -nostdlib -lgcc -mavr4 -Tdata=0x00800200 | ||
+ | |||
+ | main.lss: main.elf | ||
+ | -avr-objdump -h -S main.elf | ||
+ | |||
+ | main.hex: main.elf | ||
+ | avr-objcopy -O ihex $< $@ | ||
+ | |||
+ | sizedummy: main.elf | ||
+ | -avr-size --format=avr --mcu=atmega8 main.elf | ||
+ | |||
+ | clean: | ||
+ | $(RM) *.o leds *.ihex *.ali *.elf *.hex *.lss *.map | ||
+ | </ | ||
+ | The most important line is: | ||
+ | < | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | ===== Setting up GPS ===== | ||
+ | GPS (GNAT Programming Studio) is an editor maintained by AdaCore and it's default editor for software written in Ada. If makefile is present it is easy to use it to develop embedded software in Ada. | ||
+ | - Select '' | ||
+ | - Select '' | ||
+ | - Select '' | ||
+ | - Assure that command in text box is '' | ||
+ | - Select '' | ||
+ | - Assure that command in text box is '' | ||
+ | - Now code can be generated and run just like in any other Ada project. | ||
+ | ===== Useful code samples ===== | ||
+ | Following code samples are written and tested for ATmega8 device. | ||
+ | |||
+ | |||
+ | ==== Lighting LED ==== | ||
+ | Assuming LED anode is connected to AtMega8 PORTB pin 0 and cathode is connected to the power rail trough appropriate resistor. | ||
+ | < | ||
+ | with Interfaces; use Interfaces; | ||
+ | with AVR.AtMega8; | ||
+ | |||
+ | procedure Main is | ||
+ | |||
+ | -- LED | ||
+ | | ||
+ | for LedPort' | ||
+ | | ||
+ | |||
+ | begin | ||
+ | |||
+ | -- Initialize | ||
+ | DDRB := 1; -- only pin 0 is output | ||
+ | |||
+ | -- turn on | ||
+ | | ||
+ | |||
+ | -- turn off | ||
+ | | ||
+ | |||
+ | -- toogle | ||
+ | | ||
+ | |||
+ | -- infinite loop: end of program | ||
+ | loop end loop; | ||
+ | |||
+ | end Main; | ||
+ | |||
+ | </ | ||
+ | ==== Using interrupts ==== | ||
+ | avr-interrupts.adb | ||
+ | < | ||
+ | -- Maciej Kucia Krakow 2012 | ||
+ | -- MIT/X11 license | ||
+ | |||
+ | with System.Machine_Code; | ||
+ | |||
+ | package body AVR.Interrupts is | ||
+ | |||
+ | | ||
+ | begin | ||
+ | System.Machine_Code.Asm (" | ||
+ | end Enable; | ||
+ | |||
+ | | ||
+ | begin | ||
+ | System.Machine_Code.Asm (" | ||
+ | end Disable; | ||
+ | |||
+ | end AVR.Interrupts; | ||
+ | </ | ||
+ | avr-interrupts.ads | ||
+ | < | ||
+ | -- Maciej Kucia Krakow 2012 | ||
+ | -- MIT/X11 license | ||
+ | |||
+ | package AVR.Interrupts is | ||
+ | |||
+ | -- Enables interrupts | ||
+ | | ||
+ | -- Disables interrupts | ||
+ | | ||
+ | |||
+ | private | ||
+ | | ||
+ | | ||
+ | |||
+ | end AVR.Interrupt; | ||
+ | </ | ||
+ | ==== Buffered interrupt driven UART ==== | ||
+ | |||
+ | avr-uart.ads | ||
+ | < | ||
+ | with AVR.strings; | ||
+ | with System; | ||
+ | |||
+ | package AVR.UART is | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | -- wypisuje znak | ||
+ | | ||
+ | | ||
+ | |||
+ | -- zwraca ilosc znakow w | ||
+ | | ||
+ | |||
+ | -- wczytuje znakow w buforze wejsciowym | ||
+ | | ||
+ | | ||
+ | |||
+ | -- wypisuje lancuch znakow | ||
+ | | ||
+ | | ||
+ | |||
+ | -- wypisuje liczbe | ||
+ | | ||
+ | |||
+ | -- Wysyla znaki z bufora | ||
+ | | ||
+ | |||
+ | private | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | Line : Integer); | ||
+ | | ||
+ | |||
+ | end AVR.UART; </ | ||
+ | |||
+ | avr-uart.adb | ||
+ | < | ||
+ | with AVR.atmega8; | ||
+ | with AVR.strings; | ||
+ | with AVR.Interrupt; | ||
+ | with Environment; | ||
+ | |||
+ | package body AVR.UARTis | ||
+ | |||
+ | type Unsigned_3 | ||
+ | for Unsigned_3' | ||
+ | |||
+ | type Unsigned_4 | ||
+ | for Unsigned_4' | ||
+ | |||
+ | -- Bufory cykliczne | ||
+ | |||
+ | type TablicaUART8 is array (0..7) of Unsigned_8; | ||
+ | type TablicaUART16 is array (0..15) of Unsigned_8; | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | rec : Unsigned_8; | ||
+ | begin | ||
+ | while (UCSRA and UCSRA_RXC) = 0 loop null; end loop; | ||
+ | rec := UDR; | ||
+ | --UDR := rec; --echo | ||
+ | |||
+ | if BuffWeC <= 8 then | ||
+ | | ||
+ | | ||
+ | | ||
+ | end if; | ||
+ | Flaga_A := True; | ||
+ | end USART_RxComplete; | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | begin | ||
+ | if BuffWyC > 0 then | ||
+ | while (UCSRA and UCSRA_UDRE) = 0 loop null; end loop; | ||
+ | UDR := BuffWy(Integer(BuffWyK)); | ||
+ | | ||
+ | | ||
+ | else | ||
+ | UCSRB := UCSRB and not (UCSRB_UDRIE); | ||
+ | end if; | ||
+ | end USART_TxComplete; | ||
+ | |||
+ | |||
+ | | ||
+ | begin | ||
+ | return Integer(BuffWeC); | ||
+ | end; | ||
+ | |||
+ | -- Zamiany typow | ||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | | ||
+ | Source => Character); | ||
+ | |||
+ | | ||
+ | begin | ||
+ | if BuffWyC < 16 then | ||
+ | | ||
+ | | ||
+ | | ||
+ | end if; | ||
+ | end Write; | ||
+ | |||
+ | | ||
+ | begin | ||
+ | Write(To_Uint8(char)); | ||
+ | end WriteChar; | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | help : Integer range 0..9 :=0; | ||
+ | tmp : Integer := i; | ||
+ | arr : array (0..9) of Character; | ||
+ | begin | ||
+ | |||
+ | if tmp < 0 then WriteChar(' | ||
+ | |||
+ | if tmp = 0 then WriteChar(' | ||
+ | else | ||
+ | |||
+ | while tmp /= 0 loop | ||
+ | arr(help) := characters( tmp mod b ); | ||
+ | tmp := tmp / b; | ||
+ | |||
+ | help := help+1; | ||
+ | end loop; | ||
+ | |||
+ | while help /=0 loop | ||
+ | WriteChar(arr(help-1)); | ||
+ | help := help - 1; | ||
+ | end loop; | ||
+ | |||
+ | end if; | ||
+ | |||
+ | end WriteInteger; | ||
+ | |||
+ | | ||
+ | begin | ||
+ | -- Aktywacja przerwania | ||
+ | if ( BuffWyC > 0) then | ||
+ | UCSRB := UCSRB or UCSRB_UDRIE; | ||
+ | end if; | ||
+ | end ProcessWrite; | ||
+ | |||
+ | -- wypisuje lancuch znakow na uart | ||
+ | | ||
+ | begin | ||
+ | for I in str' | ||
+ | | ||
+ | end loop; | ||
+ | end WriteString; | ||
+ | |||
+ | -- odczyt z pamieci | ||
+ | | ||
+ | Result : Unsigned_8; | ||
+ | begin | ||
+ | Asm ("lpm %0, Z", | ||
+ | | ||
+ | | ||
+ | return Result; | ||
+ | end Get_PGM_Byte; | ||
+ | |||
+ | | ||
+ | U : Unsigned_8; | ||
+ | begin | ||
+ | U := Get_PGM_Byte (Addr); | ||
+ | return Character' | ||
+ | end Get_PGM_Char; | ||
+ | |||
+ | -- wypisuje lancuch znakow z pamieci programu | ||
+ | | ||
+ | C : Character; | ||
+ | begin | ||
+ | for U in str' | ||
+ | C := Get_PGM_Char (str (U)' | ||
+ | | ||
+ | end loop; | ||
+ | end WriteStringP; | ||
+ | |||
+ | | ||
+ | ret : Unsigned_8; | ||
+ | begin | ||
+ | if BuffWeC > 0 then | ||
+ | ret := BuffWe(Integer(BuffWeP)); | ||
+ | | ||
+ | | ||
+ | | ||
+ | else | ||
+ | | ||
+ | end if; | ||
+ | end Read; | ||
+ | |||
+ | -- Odczyt znaku z bufora | ||
+ | | ||
+ | begin | ||
+ | return To_Char(Read); | ||
+ | end ReadChar; | ||
+ | |||
+ | -- Initializacja UART | ||
+ | | ||
+ | begin | ||
+ | -- Uruchamiam moduly odbiorczy i nadawczy USART | ||
+ | UCSRB := UCSRB or UCSRB_RXEN or UCSRB_TXEN or UCSRB_RXCIE | ||
+ | -- 8 bit 1 bit stopu | ||
+ | UCSRC := UCSRC or UCSRC_URSEL or UCSRC_UCSZ0 or UCSRC_UCSZ1; | ||
+ | -- Wczytuje poprzednio obliczone wartosci baud | ||
+ | --UBRRH := 0; | ||
+ | UBRRL := 51; !!!!!!!!!!!!!!!!1 | ||
+ | |||
+ | BuffWe(0): | ||
+ | BuffWy(0): | ||
+ | end; | ||
+ | |||
+ | |||
+ | | ||
+ | | ||
+ | Line : Integer) | ||
+ | is begin | ||
+ | null; | ||
+ | -- error handling here | ||
+ | end Last_Chance_Handler; | ||
+ | |||
+ | end AVR.UART;</ | ||
+ | |||
+ | Example: | ||
+ | < | ||
+ | ==== Storing strings in program memory ==== | ||
+ | < | ||
+ | -- Maciej Kucia Krakow 2012 | ||
+ | -- | ||
+ | |||
+ | with Interfaces; use Interfaces; | ||
+ | |||
+ | package AVR.strings is | ||
+ | |||
+ | type AVR_String is array (Unsigned_8 range <>) of Character; | ||
+ | type Progmem_String is new AVR_String; | ||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | end AVR.strings; | ||
+ | </ | ||
+ | |||
+ | ==== Timer0 PWM ==== | ||
+ | avr-timer0pwm.ads | ||
+ | < | ||
+ | |||
+ | package AVR.TIMER0PWM is | ||
+ | |||
+ | -- inicjalizuje timer0 w trybie PWM | ||
+ | | ||
+ | |||
+ | -- ustawia wypelnienie PWM | ||
+ | | ||
+ | |||
+ | private | ||
+ | | ||
+ | | ||
+ | |||
+ | end AVR.TIMER0PWM; | ||
+ | |||
+ | ada-timer0pwm.adb | ||
+ | < | ||
+ | |||
+ | package body AVR.TIMER0PWM is | ||
+ | |||
+ | | ||
+ | begin | ||
+ | -- Tumer setup | ||
+ | OCR1AH :=0; | ||
+ | OCR1AL :=0; | ||
+ | OCR1BH :=0; | ||
+ | OCR1BL :=0; | ||
+ | TCCR1A := TCCR1A_WGM10 or TCCR1A_COM1A1; | ||
+ | TCCR1B := TCCR1B_WGM12 or TCCR1B_CS10; | ||
+ | end InitPWM; | ||
+ | |||
+ | | ||
+ | begin | ||
+ | OCR1AH := val; | ||
+ | OCR1AL := val; | ||
+ | end SetPWM; | ||
+ | |||
+ | end AVR.TIMER0PWM; | ||
+ | |||
+ | ==== TWI interface ==== | ||
+ | |||
+ | avr-twi.ads | ||
+ | < | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | private | ||
+ | | ||
+ | |||
+ | end AVR.TWI; </ | ||
+ | |||
+ | avr-twi.adb | ||
+ | < | ||
+ | with Environment; | ||
+ | |||
+ | package body AVR.TWI is | ||
+ | |||
+ | -- Start | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | -- trans | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | -- rec | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | begin | ||
+ | -- Init twi prescaler and bitrate | ||
+ | TWSR := 0; | ||
+ | TWBR := Interfaces.Unsigned_8 ( ((Environment.F_CPU / TWI_FREQ) - 16 ) /2 ); | ||
+ | end Init; | ||
+ | |||
+ | -- zwraca false gdy failed | ||
+ | | ||
+ | twst : Unsigned_8; | ||
+ | begin | ||
+ | |||
+ | --Send start | ||
+ | TWCR := TWCR_TWINT or TWCR_TWSTA or TWCR_TWEN; | ||
+ | |||
+ | -- czekaj | ||
+ | while ( (TWCR and TWCR_TWINT) = 0) loop null; end loop; | ||
+ | |||
+ | twst := TWSR and TW_STATUS_MASK and 16#F8#; | ||
+ | |||
+ | -- sprawdzam odpowiedz | ||
+ | if ( twst /= TW_START) and ( twst /= TW_REP_START ) then return false; end if; | ||
+ | |||
+ | -- Wysylam adress | ||
+ | TWDR := address; | ||
+ | TWCR := TWCR_TWINT or TWCR_TWEN; | ||
+ | |||
+ | -- czekam | ||
+ | while ( (TWCR and TWCR_TWINT) =0 ) loop null; end loop; | ||
+ | |||
+ | -- sprawdzam | ||
+ | twst := TWSR and TW_STATUS_MASK and 16#F8#; | ||
+ | |||
+ | if ( (twst /= TW_MT_SLA_ACK) and (twst /= TW_MR_SLA_ACK) ) then return false; end if; | ||
+ | |||
+ | return true; | ||
+ | |||
+ | end Start; | ||
+ | |||
+ | | ||
+ | begin | ||
+ | TWCR := TWCR_TWINT or TWCR_TWEN or TWCR_TWSTO; | ||
+ | while (( TWCR and TWCR_TWSTO ) /= 0) loop null; end loop; | ||
+ | end Stop; | ||
+ | |||
+ | -- true jezeli sie powiodlo | ||
+ | | ||
+ | twst : Unsigned_8; | ||
+ | begin | ||
+ | |||
+ | TWDR := data; | ||
+ | |||
+ | TWCR := TWCR_TWINT or TWCR_TWEN; | ||
+ | |||
+ | while ( (TWCR and TWCR_TWINT) = 0 ) loop null; end loop; | ||
+ | |||
+ | twst := TWSR and TW_STATUS_MASK and 16#F8#; | ||
+ | if (twst /= TW_MT_DATA_ACK) then | ||
+ | | ||
+ | end if; | ||
+ | |||
+ | return true; | ||
+ | |||
+ | end Write; | ||
+ | |||
+ | | ||
+ | begin | ||
+ | |||
+ | TWCR := TWCR_TWINT or TWCR_TWEN or TWCR_TWEA; | ||
+ | |||
+ | while ( (TWCR and TWCR_TWINT) = 0 ) loop null; end loop; | ||
+ | |||
+ | return TWDR; | ||
+ | |||
+ | end ReadAck; | ||
+ | |||
+ | | ||
+ | begin | ||
+ | |||
+ | TWCR := TWCR_TWINT or TWCR_TWEN; | ||
+ | |||
+ | while ( (TWCR and TWCR_TWINT) = 0 ) loop null; end loop; | ||
+ | |||
+ | return TWDR; | ||
+ | |||
+ | end ReadNak; | ||
+ | |||
+ | end AVR.TWI;</ | ||
+ | |||
+ | ==== Watchdog ==== | ||
+ | |||
+ | avr-watchdog.ads | ||
+ | < | ||
+ | |||
+ | type Watchdog_Timeout is | ||
+ | ( | ||
+ | WT16k, | ||
+ | WT32k, | ||
+ | WT64k, | ||
+ | WT128k, | ||
+ | WT256k, | ||
+ | WT512k, | ||
+ | WT1024k, | ||
+ | WT2048k | ||
+ | ); | ||
+ | for Watchdog_Timeout' | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | private | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | end AVR.Watchdog;</ | ||
+ | |||
+ | avr-watchdog.adb | ||
+ | < | ||
+ | with AVR.AtMega8; | ||
+ | |||
+ | package body AVR.Watchdog is | ||
+ | |||
+ | | ||
+ | new Ada.Unchecked_Conversion (Watchdog_Timeout, | ||
+ | |||
+ | | ||
+ | begin | ||
+ | WDTCR := WDTCR or WDTCR_WDCE or WDTCR_WDE or WT2Uint8(tout); | ||
+ | WDTCR := WDTCR or WDTCR_WDCE or WDTCR_WDE or WT2Uint8(tout); | ||
+ | end Enable; | ||
+ | |||
+ | | ||
+ | begin | ||
+ | WDTCR := WDTCR or WDTCR_WDCE or WDTCR_WDE; | ||
+ | WDTCR := 0; | ||
+ | end Disable; | ||
+ | |||
+ | | ||
+ | begin | ||
+ | Asm (" | ||
+ | end Wdr; | ||
+ | |||
+ | end AVR.Watchdog;</ |
projects/avrada.txt · Last modified: 2012/08/05 11:02 by mkucia