Hi,
I am working on a project where I need to use the timer-1 interrupt of Olinuxino A13. I have successfully initialized the timer also enabled the timer-1 interrupt.
Can someone help me with writing the Interrupt Service Routine (ISR) for the timer-1 interrupt.
This is my C code so far,
/////////////////////////////////////////////////////////////
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <pthread.h>
#include <unistd.h>
#include <sched.h>
#define GPIO_BASE 0x01C20800
#define PWM_BASE 0x01C20C00
#define INT_BASE 0x01C20400
unsigned int *portGConfig;
unsigned int *portGData;
unsigned int *portBConfig;
unsigned int *PWMControl;
unsigned int *PWMPeriod;
unsigned int *TimerIRQEn;
unsigned int *TimerStatus;
unsigned int *Timer1Control;
unsigned int *Timer1Interval;
unsigned int *Timer1Current;
unsigned int *IntVector;
unsigned int *IntBaseAddr;
unsigned int *IntProtect;
unsigned int *IntControl;
unsigned int *IntIRQP0;
unsigned int *IntIRQP1;
unsigned int *IntIRQP2;
unsigned int *IntFIQP0;
unsigned int *IntFIQP1;
unsigned int *IntFIQP2;
unsigned int *IntSel0;
unsigned int *IntSel1;
unsigned int *IntSel2;
unsigned int *IntEn0;
unsigned int *IntEn1;
unsigned int *IntEn2;
unsigned int *IntMask0;
unsigned int *IntMask1;
unsigned int *IntMask2;
unsigned int *IntResp0;
unsigned int *IntResp1;
unsigned int *IntResp2;
unsigned int *IntForce0;
unsigned int *IntForce1;
unsigned int *IntForce2;
unsigned int *IntScrPr0;
unsigned int *IntScrPr1;
unsigned int *IntScrPr2;
unsigned int *IntScrPr3;
unsigned int *IntScrPr4;
unsigned int *IntScrPr5;
static unsigned int GPIO_MMAP = 0;
static unsigned int PWM_MMAP = 0;
static unsigned int TIMER_MMAP = 0;
static unsigned int INT_MMAP = 0;
int main(void)
{
////////////////////////////_MEMORY_MAPPING_////////////////////////////
int fd;
unsigned int addr_start, addr_offset, pwm_offset, int_offset;
unsigned int PageSize, PageMask;
void *pc;
fd = open("/dev/mem", O_RDWR);
if(fd < 0) { perror("Unable to open /dev/mem"); }
PageSize = sysconf(_SC_PAGESIZE);
PageMask = (~(PageSize-1));
addr_start = GPIO_BASE & PageMask;
addr_offset = GPIO_BASE & ~PageMask;
pwm_offset = PWM_BASE & ~PageMask;
int_offset = INT_BASE & ~PageMask;
pc = (void *)mmap(0, PageSize*2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, addr_start);
if(pc == MAP_FAILED) { perror("Unable to mmap file"); }
GPIO_MMAP = (unsigned int)pc;
GPIO_MMAP += addr_offset;
PWM_MMAP = (unsigned int)pc;
PWM_MMAP += pwm_offset;
TIMER_MMAP = PWM_MMAP;
INT_MMAP = (unsigned int)pc;
INT_MMAP += int_offset;
close(fd);
if(fd == -1) { perror("Unable to close file"); }
////////////////////////////_GPIO_CONFIG_////////////////////////////
portGConfig = (unsigned int *)(GPIO_MMAP + 0xDC);
portGData = (unsigned int *)(GPIO_MMAP + 0xE8);
*portGConfig = 0x1110; //configure port G pin 9 to output
if (*portGData == 0x6) *portGData = 0x200; else *portGData = 0x000;
////////////////////////////_PWM_CONFIG_////////////////////////////
portBConfig = (unsigned int *)(GPIO_MMAP + 0x24);
PWMControl = (unsigned int *)(PWM_MMAP + 0x200);
PWMPeriod = (unsigned int *)(PWM_MMAP + 0x204);
*portBConfig = 0x200; //Configure Port B pin 2 to PWM
*PWMControl = 0x00; //printf("PWM cleared\n");
*PWMControl |= 0x00000020; //printf("PWM High Level\n");
*PWMControl |= 0x00000002; //printf("PWM 24MHz/240 = 100kHz\n");
*PWMControl |= 0x00000040; //printf("PWM Gating = pass\n");
*PWMControl |= 0x00000010; //printf("PWM Enabled\n");
*PWMPeriod = 0x01F30064; //printf("PWM period 0x01F30064\n");
////////////////////////////_TIMER_1_CONFIG_////////////////////////////
TimerIRQEn = (unsigned int *)(TIMER_MMAP + 0x00);
TimerStatus = (unsigned int *)(TIMER_MMAP + 0x04);
Timer1Control = (unsigned int *)(TIMER_MMAP + 0x20);
Timer1Interval = (unsigned int *)(TIMER_MMAP + 0x24);
Timer1Current = (unsigned int *)(TIMER_MMAP + 0x28);
*TimerIRQEn |= 0x02; //printf("*TimerIRQEn = 0x%x\n", *TimerIRQEn);
*Timer1Control = 0x04; //printf("*Timer1Control = 0x%x\n", *Timer1Control);
*TimerStatus = 0x02; //printf("*TimerStatus = 0x%x\n", *TimerStatus);
*Timer1Interval = 0x16E3600; //printf("*Timer1Interval = 0x%x\n", *Timer1Interval);
*Timer1Current = 0x16E3600; //printf("*Timer1Current = 0x%x\n", *Timer1Current);
*Timer1Control = 0x05; //printf("*Timer1Control = 0x%x\n", *Timer1Control);
////////////////////////////_INTERRUPT_REGISTERS_////////////////////////////
IntVector = (unsigned int *)(INT_MMAP + 0x00); printf("*IntVector = 0x%x\n", *IntVector);
IntBaseAddr = (unsigned int *)(INT_MMAP + 0x04); printf("*IntBaseAddr = 0x%x\n", *IntBaseAddr);
IntProtect = (unsigned int *)(INT_MMAP + 0x08); printf("*IntProtect = 0x%x\n", *IntProtect);
IntControl = (unsigned int *)(INT_MMAP + 0x0C); printf("*IntControl = 0x%x\n", *IntControl);
IntIRQP0 = (unsigned int *)(INT_MMAP + 0x10); printf("*IntIRQP0 = 0x%x\n", *IntIRQP0);
IntIRQP1 = (unsigned int *)(INT_MMAP + 0x14); printf("*IntIRQP1 = 0x%x\n", *IntIRQP1);
IntIRQP2 = (unsigned int *)(INT_MMAP + 0x18); printf("*IntIRQP2 = 0x%x\n", *IntIRQP2);
IntFIQP0 = (unsigned int *)(INT_MMAP + 0x20); printf("*IntFIQP0 = 0x%x\n", *IntFIQP0);
IntFIQP1 = (unsigned int *)(INT_MMAP + 0x24); printf("*IntFIQP1 = 0x%x\n", *IntFIQP1);
IntFIQP2 = (unsigned int *)(INT_MMAP + 0x28); printf("*IntFIQP2 = 0x%x\n", *IntFIQP2);
IntSel0 = (unsigned int *)(INT_MMAP + 0x30); printf("*IntSel0 = 0x%x\n", *IntSel0);
IntSel1 = (unsigned int *)(INT_MMAP + 0x34); printf("*IntSel1 = 0x%x\n", *IntSel1);
IntSel2 = (unsigned int *)(INT_MMAP + 0x38); printf("*IntSel2 = 0x%x\n", *IntSel2);
IntEn0 = (unsigned int *)(INT_MMAP + 0x40); printf("*IntEn0 = 0x%x\n", *IntEn0);
IntEn1 = (unsigned int *)(INT_MMAP + 0x44); printf("*IntEn1 = 0x%x\n", *IntEn1);
IntEn2 = (unsigned int *)(INT_MMAP + 0x48); printf("*IntEn2 = 0x%x\n", *IntEn2);
IntMask0 = (unsigned int *)(INT_MMAP + 0x50); printf("*IntMask0 = 0x%x\n", *IntMask0);
IntMask1 = (unsigned int *)(INT_MMAP + 0x54); printf("*IntMask1 = 0x%x\n", *IntMask1);
IntMask2 = (unsigned int *)(INT_MMAP + 0x58); printf("*IntMask2 = 0x%x\n", *IntMask2);
IntResp0 = (unsigned int *)(INT_MMAP + 0x60); printf("*IntResp0 = 0x%x\n", *IntResp0);
IntResp1 = (unsigned int *)(INT_MMAP + 0x64); printf("*IntResp1 = 0x%x\n", *IntResp1);
IntResp2 = (unsigned int *)(INT_MMAP + 0x68); printf("*IntResp2 = 0x%x\n", *IntResp2);
IntForce0 = (unsigned int *)(INT_MMAP + 0x70); printf("*IntForce0 = 0x%x\n", *IntForce0);
IntForce1 = (unsigned int *)(INT_MMAP + 0x74); printf("*IntForce1 = 0x%x\n", *IntForce1);
IntForce2 = (unsigned int *)(INT_MMAP + 0x78); printf("*IntForce2 = 0x%x\n", *IntForce2);
IntScrPr0 = (unsigned int *)(INT_MMAP + 0x80); printf("*IntScrPr0 = 0x%x\n", *IntScrPr0);
IntScrPr1 = (unsigned int *)(INT_MMAP + 0x84); printf("*IntScrPr1 = 0x%x\n", *IntScrPr1);
IntScrPr2 = (unsigned int *)(INT_MMAP + 0x88); printf("*IntScrPr2 = 0x%x\n", *IntScrPr2);
IntScrPr3 = (unsigned int *)(INT_MMAP + 0x8C); printf("*IntScrPr3 = 0x%x\n", *IntScrPr3);
IntScrPr4 = (unsigned int *)(INT_MMAP + 0x90); printf("*IntScrPr4 = 0x%x\n", *IntScrPr4);
IntScrPr5 = (unsigned int *)(INT_MMAP + 0x94); printf("*IntScrPr5 = 0x%x\n", *IntScrPr5);
}
/////////////////////////////////////////////////////////////
In my code the timer-1 successfully works. Now I need to write a code to run when the timer-1 interrupt occurs.
I am new in interrupt code writing. I have once written an ISR for 8051. I am not sure how to write the code for Olinuxino A13 using the GCC compiler.
In other words, how do I link the timer-1 vector address, which is 0x005C, with the code I want to run.
say for example I want to Turn On and Off the on board LED (GPIO-2 Pin-9) when the timer-1 interrupt occurs.
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
if (*portGData == 0x6) *portGData = 0x200; else *portGData = 0x000;
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
Please help. Thanks.
In Linux, AFAIK, there is no way to serve interrupts from the userspace, you have to write a kernel module.
PS: If you just want to blink the LED, there is a much easier way using sunxi_led driver (see https://www.olimex.com/forum/index.php?topic=3156.msg13226#msg13226 (https://www.olimex.com/forum/index.php?topic=3156.msg13226#msg13226)).
The only alternative is to use the mechanism provided by functions select()/poll()
http://man7.org/linux/man-pages/man2/poll.2.html (http://man7.org/linux/man-pages/man2/poll.2.html)
http://linux.die.net/man/2/select (http://linux.die.net/man/2/select)
You also can to use UIO:
https://www.kernel.org/doc/htmldocs/uio-howto/about.html (https://www.kernel.org/doc/htmldocs/uio-howto/about.html)