02 ARM SAM4 – pierwszy program

Celem pierwszego programu będzie cykliczne zapalenie i gaszenie dwóch diód znajdujących się na zestawie uruchomieniowym SAM4XPlained. Do programowania układu posłuży wbudowany w zestaw programator J-Link. Do napisaniu pierwszego programu posłuży nam środowiska Atmel Studio 7.0 do pobrania z poniższego adresu:

http://www.atmel.com/tools/atmelstudio.aspx

Płytka jest wyposażona w  dwie dostępne bezpośrednio diody led oznaczone na poniższym zdjęciu jako LED1 oraz LED2.

 

Diody podłączone są do w/w PC10 oraz PC17 według poniższego schematu, ponieważ podłączone są do zasilania, to podając logiczne jedne na wyjście np. PC10 gasimy diodę, a podając logiczne 0 ją zapalamy:

Możemy teraz przejść do tworzenia nowego programu. Z zakładki File->New->Project… wybieramy projekt typu GCC C Exexcutable Project,

a następnie z listy procesorów wybieramy ATSAM4S16C.

Program automatycznie utworzy nam kod programu jak poniżej zawierający następujące ważne dla nas elementy. #include „sam.h” – za pomocą tej komendy do programu zostanie podłączony zestaw definicji rejestrów dla procesorów typu sam. SystemInit(); – załącza na działanie naszego procesora

#include „sam.h”

int main(void)
{
/* Initialize the SAM system */
SystemInit();

/* Replace with your application code */
while (1)
{
}
}

Uruchomienie poniższego programu nic nie spowoduje, musimy teraz uruchomić odpowiednie rejestry w procesorze, które spowodują podanie napięcia na interesującą nas nóżkę PC10.

Procesor podzielony jest na rejestry A,B,C każdy z nich obsuguje własny zestaw wejść i wyjść.

Na początku musimy uruchomić interesujący na rejestr C poprzez wpisanie wartości 1 w odpowiedni bit pamięci. Poniżej adresy uruchamiające odpowiednie rejestry:

PIO Enable Register (SAM4S Series Datascheet – page 588)

PIOA – 0x400E0E00

PIOB – 0x400E1000

PIOC – 0x400E1200

każdy z tych adresów przechowuje zmienną 32 bitową, aby uruchomić w/w PC10 muismy ustawić 10bit jako aktywny, robimy to poniższą formułą.

(*(volatile unsigned int*)0x400E1200U) = 1<<10;

następną rzeczą którą musimy wykonać to ustawić rejest jako wyjście, służ do tego poniże adresy:

PIO Output Enable Register (SAM4S Series Datascheet – page 592)

PIOA – 0x400E0E10

PIOB – 0x400E1010

PIOC – 0x400E1210

rejestr PC10 ustawiamy poniższą formułą:

(*(volatile unsigned int*)0x400E1210U) = 1<<10;

,musimy też ustawić rezystor podciągający w pozycji 0

PIO Pull-Up Disabled Register (SAM4S Series Datascheet – page 608)

PIOA – 0x400E0E60

PIOB – 0x400E1060

PIOC – 0x400E1260

rejestr PC10 ustawiamy poniższą formułą:

(*(volatile unsigned int*)0x400E1260U) = 1<<10;

, następnie przechodzimy do  adresów który umożliwią nam wystawienie logicznej jedynki na dowolne wyjście:

PIO Set Output Data Register (SAM4S Series Datascheet – page 597)

PIOA – 0x400E0E30

PIOB – 0x400E1030

PIOC – 0x400E1230

rejestr PC10 ustawiamy poniższą formułą:

(*(volatile unsigned int*)0x400E1230U) = 1<<10;

teraz udało się nam zapalić diodę, aby ją zgasić musimy wyczyścić rejestr za pomocą poniższych adresów:

PIO Clear Output Data Register (SAM4S Series Datascheet – page 598)

PIOA – 0x400E0E34

PIOB – 0x400E1034

PIOC – 0x400E1234

rejestr PC10 ustawiamy poniższą formułą:

(*(volatile unsigned int*)0x400E1234U) = 1<<10;

do zakończenia pracy potrzebujemy formułę która będzie nam odliczała czas pomiędzy zapalaniem i gaśnięciem diody. Zrobimy to przy użyciu pętli for jak poniżej:

for(uint32_t i=0; i<2000000;i++) {}

zmiennna i jest zmienną 32 bitową typu uint32_t i obliczenia na niej wykonują się w jednym takcie zegara, w przypadku procesorów AVR wymagane było kilka taktów na taką zmienną.

cały program powinien mieć poniższą składnie:

#include „sam.h”

int main(void)

{

SystemInit();

(*(volatile unsigned int*)0x400E1200U) = 1<<10;

(*(volatile unsigned int*)0x400E1210U) = 1<<10;

(*(volatile unsigned int*)0x400E1260U) = 1<<10;

while (1)

{

(*(volatile unsigned int*)0x400E1230U) = 1<<10;

for(uint32_t i=0; i<2000000;i++) {}

(*(volatile unsigned int*)0x400E1230U) = 1<<10;

for(uint32_t i=0; i<2000000;i++) {}

}

}

Teraz możemy przejść do uproszczania naszego programu, na codzień cieżko jest programować podając adresy rejestrów, czy numery pinów, dlatego możemy te elementy zdefiniować czytelnymi dla nas skrótami. Rozbudujemy też nasz program o zapalanie diód na przemiennie. Do zdefioniowania uproszczonych definicji służy instrukcja #define, a poniższa składania przypisze nam pin 10 do diody A oraz pin 17 do diody B.

#define LEDA  (1<<10)

#define LEDB  (1<<17)

Od teraz zamiast zapisu 1<<10 stosujemy zapis LED_A.

Możemy też uprościć adresowania rejestrów w pamięcie. Ich definicje znajdują się w pliku sam4sh16.h który jest wywołąny przez plik sam.h. I tak, uruchomienie portu które dotychczas wyglądało tak:

(*(volatile unsigned int*)0x400E1200U) = 1<<10;

zastępujemy uproszczonym zapisem:

PIOC->PIO_PER = LEDA;

oczywiście, są też rejestry PIOA oraz PIOB, ale my ich narazie nie wykorzystujemy, jeśli chcemy uruchomić rejestr dla dwóch diód, możemy zrobić to tak:

PIOC->PIO_PER = LEDA;

PIOC->PIO_PER = LEDB;

lub prościej tak:

PIOC->PIO_PER = (LEDA | LEDB);

poniżej definicje dla wykorzystywanych przez nas pozostałych adresów:

(*(volatile unsigned int*)0x400E1210U) = 1<<10 teraz możemy

PIOC->PIO_OER = LEDA;

(*(volatile unsigned int*)0x400E1260U) = 1<<10 teraz możemy

PIOC->PIO_PUDR = LEDA;

(*(volatile unsigned int*)0x400E1230U) = 1<<10 teraz możemy

PIOC->PIO_SODR = LEDA;

(*(volatile unsigned int*)0x400E1234U) = 1<<10 teraz możemy

PIOC->PIO_CODR = LEDA;

Poniżej przykład zooptymalizowanego programu:

#include "sam.h"
 #define LEDA (1<<10)
 #define LEDB (1<<17)

 int main(void)

{

/* Initialize the SAM system */

SystemInit();

 PIOC->PIO_PER = (LEDA | LEDB);
 PIOC->PIO_OER = (LEDA | LEDB);
 PIOC->PIO_PUDR = (LEDA | LEDB);

/* Replace with your application code */
 while (1)
 {
 PIOC->PIO_SODR = LEDA;
 PIOC->PIO_CODR = LEDB;
 for(uint32_t i=0; i<250000;i++) { }

PIOC->PIO_SODR = LEDB;
 PIOC->PIO_CODR = LEDA;
 for(uint32_t i=0; i<250000;i++)  {}
 }
 }

example.c



#include „sam.h”
#define LEDA (1<<10)
#define LEDB (1<<17) int main(void) { /* Initialize the SAM system */ SystemInit(); PIOC->PIO_PER = (LEDA | LEDB);
PIOC->PIO_OER = (LEDA | LEDB);
PIOC->PIO_PUDR = (LEDA | LEDB);

/* Replace with your application code */
while (1)
{
PIOC->PIO_SODR = LEDA;
PIOC->PIO_CODR = LEDB;
for(uint32_t i=0; i<250000;i++) { } PIOC->PIO_SODR = LEDB;
PIOC->PIO_CODR = LEDA;
for(uint32_t i=0; i<250000;i++)  {}
}
}

Autor: Kwiatkowski Dawid

kontakt: dawid@3dpart.pl