Никак не могу найти ошибку из-за которой процессор зависает при записи в регистры PIOC.
Плата Portux G20 http://www.taskit.de/en/products/portuxg20/index.htm с Atmel AT91SAM9G20 с Angstrom Linux.
У этого процессора есть три линии конфигурируемых input/output линий по 32 на каждой линии PIOA, PIOB и PIOC.
Сдвиг на PIOB =$FFFFF600, PIOC=$FFFFF800. Сдвиг на регистры конфигурации
PER= $0000 //enable registr
OER=$0010 //enable output registr
IFDR=$0024 //enable filtr registr
SODR=$0030 //set ouput register - set high on output
CODR=$0034 //clear output registr - set low on output
IDR=$0044 //disable interrupt registr
Все регистры 32-х битные.
При записи в регистры линии PIOC процессор зависает.
Пример кода на С работает без проблем.
Мой код на Паскале
- Код: Выделить всё
program project1;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils,BaseUnix,crt,errors
{ you can add units after this };
const
//map consts
MAP_SIZE=4096;
MAP_MASK=(MAP_SIZE-1);
//BASE ADDRESS OF PIOB and PIOC
//calculating address due of page size 4096 = $1000 PIOB_BASE= $FFFFF600 div $1000 =$FFFFF
//calculating address due of page size 4096 = $1000 PIOB_BASE= $FFFFF800 div $1000 =$FFFFF
//page number offset
PIO_BASE=$FFFFF;
//OFFSET TO CONTROL REGISTERS REGISTERS address PIOB
PIOB_OFFSET=$600;
PIOB_PER=(PIOB_OFFSET+$0000);
PIOB_OER=(PIOB_OFFSET+$0010);
PIOB_IFDR=(PIOB_OFFSET+$0024);
PIOB_SODR=(PIOB_OFFSET+$0030);
PIOB_CODR=(PIOB_OFFSET+$0034);
PIOB_IDR=(PIOB_OFFSET+$0044);
//OFFSET TO CONTROL REGISTERS REGISTERS address PIOB
PIOC_OFFSET=$600;
PIOC_PER=(PIOC_OFFSET+$0000);
PIOC_OER=(PIOC_OFFSET+$0010);
PIOC_IFDR=(PIOC_OFFSET+$0024);
PIOC_SODR=(PIOC_OFFSET+$0030);
PIOC_CODR=(PIOC_OFFSET+$0034);
PIOC_IDR=(PIOC_OFFSET+$0044);
//set 1 on 27 pin on PIOB controller registers
PIOB_B27=(1 shl 27);
//set 1 on pin 0 on PIOC controller registers
PIOC_C00=(1 shl 0);
blink_count=5;
var
fd:cint;
mem_base:^Longword;
reg_addr:^Longword;
i:byte;
begin
//get file descriptor
fd:=fpOpen('/dev/mem',O_RdWr or O_SYNC);
if fd<0 then begin
writeln('Cant get file description');
Halt(1);
end;
writeln('/dev/mem has opened');
//map 1 page memory 4kB
//fpmmap is used page OFFSET not byte
mem_base:=fpmmap(Nil,MAP_SIZE,PROT_READ or PROT_WRITE,MAP_SHARED ,fd, PIO_BASE);
if ptrint(mem_base)=-1 then begin
writeln('Memory map error. Error: ',strerror(fpGeterrno));
Halt(2);
end;
writeln('Memory mapped on address $',hexstr(mem_base));
//работает
// setting registers to blink on pin B29
//enable registr
reg_addr:=Pointer(Longword(mem_base)+PIOB_PER);
reg_addr^:=PIOB_B27;
//disable input filtr
reg_addr:=Pointer(Longword(mem_base)+PIOB_IFDR);
reg_addr^:=PIOB_B27;
//disable interrupt
reg_addr:=Pointer(Longword(mem_base)+PIOB_IDR);
reg_addr^:=PIOB_B27;
//enable output
reg_addr:=Pointer(Longword(mem_base)+PIOB_OER);
reg_addr^:=PIOB_B27;
//blinking
for i:=0 to blink_count do begin
//set output data register
reg_addr:=Pointer(Longword(mem_base)+PIOB_SODR);
reg_addr^:=PIOB_B27;
sleep(1000);
//clear output data register
reg_addr:=Pointer(Longword(mem_base)+PIOB_CODR);
reg_addr^:=PIOB_B27;
sleep(1000);
end;
//вешает процессор
// setting registers to blink on pin C00
//enable registr
reg_addr:=Pointer(Longword(mem_base)+PIOC_PER);
reg_addr^:=PIOC_C00;
//disable input filtr
reg_addr:=Pointer(Longword(mem_base)+PIOC_IFDR);
reg_addr^:=PIOC_C00;
//disable interrupt
reg_addr:=Pointer(Longword(mem_base)+PIOC_IDR);
reg_addr^:=PIOC_C00;
//enable output
reg_addr:=Pointer(Longword(mem_base)+PIOC_OER);
reg_addr^:=PIOC_C00;
//blinking
for i:=0 to blink_count do begin
//set output data register
reg_addr:=Pointer(Longword(mem_base)+PIOC_SODR);
reg_addr^:=PIOC_C00;
sleep(1000);
//clear output data register
reg_addr:=Pointer(Longword(mem_base)+PIOC_CODR);
reg_addr^:=PIOC_C00;
sleep(1000);
end;
//close file descriptor
fpClose(fd);
//unmap memory
if fpMUnMap(mem_base, map_size)<>0 then Halt(fpgeterrno);
end.
Код на С
- Код: Выделить всё
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)
#define PIOB_BASE 0xfffff600UL
#define PIOC_BASE 0xfffff800UL
#define PIO_C00 ((unsigned long) 1 << 0)
#define PIO_C01 ((unsigned long) 1 << 1)
#define PIO_B27 ((unsigned long) 1 << 27)
#define PIOB_PER PIOB_BASE + 0x0000
#define PIOB_OER PIOB_BASE + 0x0010
#define PIOB_IFDR PIOB_BASE + 0x0024
#define PIOB_SODR PIOB_BASE + 0x0030
#define PIOB_CODR PIOB_BASE + 0x0034
#define PIOB_IDR PIOB_BASE + 0x0044
#define PIOC_PER PIOC_BASE + 0x0000
#define PIOC_OER PIOC_BASE + 0x0010
#define PIOC_IFDR PIOC_BASE + 0x0024
#define PIOC_SODR PIOC_BASE + 0x0030
#define PIOC_CODR PIOC_BASE + 0x0034
#define PIOC_IDR PIOC_BASE + 0x0044
int main(int argc, char **argv) {
int fd, i, repetitions;
void *map_base;
if (argc > 1)
{
repetitions =(atoi(argv[1]));
}
else
{
printf("\nMissing argument\n");
printf("Usage: led REPETITIONS\n");
printf("REPETITIONS: int, that specifies number of repetitions of blinking led cycles\n\n\n");
exit(1);
}
if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
{
printf("Couldn't open /dev/mem.\n");
exit(1);
}
printf("/dev/mem opened.\n");
fflush(stdout);
/* Map one page */
map_base = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PIOB_BASE & ~MAP_MASK);
if(map_base == (void *) -1)
{
printf("Couldn't get Map-Address.\n");
exit(1);
}
printf("Memory mapped shift %p.\n", PIOB_BASE & ~MAP_MASK);
printf("Memory mapped at address %p.\n", map_base);
fflush(stdout);
// Configure the registers
*((unsigned long *) (map_base + (PIOB_PER & MAP_MASK))) = PIO_B27; //enable io
printf("Memory shift to PER %p.\n", PIOB_PER & MAP_MASK);
*((unsigned long *) (map_base + (PIOB_IFDR & MAP_MASK))) = PIO_B27; //disable input filter
printf("Memory shift to IFDR %p.\n", PIOB_IFDR & MAP_MASK);
*((unsigned long *) (map_base + (PIOB_IDR & MAP_MASK))) = PIO_B27; // disable interrupt
*((unsigned long *) (map_base + (PIOB_OER & MAP_MASK))) = PIO_B27; // Enable output
*((unsigned long *) (map_base + (PIOC_PER & MAP_MASK))) = PIO_C00 | PIO_C01;
*((unsigned long *) (map_base + (PIOC_IFDR & MAP_MASK))) = PIO_C00 | PIO_C01;
*((unsigned long *) (map_base + (PIOC_IDR & MAP_MASK))) = PIO_C00 | PIO_C01;
*((unsigned long *) (map_base + (PIOC_OER & MAP_MASK))) = PIO_C00 | PIO_C01;
i = 0;
while(i < repetitions)
{
*((unsigned long *) (map_base + (PIOC_CODR & MAP_MASK))) = PIO_C00;
*((unsigned long *) (map_base + (PIOB_SODR & MAP_MASK))) = PIO_B27;
sleep(1);
*((unsigned long *) (map_base + (PIOB_CODR & MAP_MASK))) = PIO_B27;
*((unsigned long *) (map_base + (PIOC_SODR & MAP_MASK))) = PIO_C01;
sleep(1);
*((unsigned long *) (map_base + (PIOC_CODR & MAP_MASK))) = PIO_C01;
*((unsigned long *) (map_base + (PIOC_SODR & MAP_MASK))) = PIO_C00;
sleep(1);
i++;
}
*((unsigned long *) (map_base + (PIOB_CODR & MAP_MASK))) = PIO_B27;
*((unsigned long *) (map_base + (PIOC_CODR & MAP_MASK))) = PIO_C00 | PIO_C01;
if(munmap(map_base, MAP_SIZE) == -1) exit(1);
close(fd);
return 0;
}
Код на Паскале компилировал на Магея Линух 3 64-бит с crossarm и fpc юнитами 2.5.1 для ARM и прямо на плате fpc 2.6.2. Результат один и тот же при записи в регистры PIOC процессор зависает. Чтение регистра возвращающего состояние (OFFSET= $0008) outputa выполняется без проблем.
Уже не зная, где искать ошибку. Может баг функции fpmmap - выделяет 512 байт вместо 4 килобайт (хотя наверно это невозможно)?
Спасибо за любую идею.