On my AT91SAM9RL-EK ARM board, running a Linux 2.6.30 buildroot, I have the following.
cat /proc/interrupts
CPU0
1: 6475 AIC at91_tick, rtc0, ttyS0
10: 11 AIC mmc0
13: 4 AIC atmel_spi.0
18: 23533 AIC tc_clkevt
20: 0 AIC atmel_tsadcc
22: 0 AIC atmel_usba_udc
23: 0 AIC atmel_lcdfb
24: 0 AIC AC97C
40: 1 GPIO atmel_usba_udc
47: 0 GPIO mmc0
64: 6 GPIO Right Click
65: 10 GPIO Left Click
The right and left click are the buttons on my board. Now I want to modify the interrupt handlers for the buttons (for example that they give me an output when clicked).
Where can I find the interrupt handlers or drivers (or the sourcefiles for them) for the buttons?
Or can I write my own drivers and register them (while I am in user-space) for the buttons and how?
This is some data from the boards guide about the PIO
IO... Per.... Application Usage............................................ Pow. by
PB0 TXD3 USER’S PUSH BUTTON 1 PB0 as LEFT CLICK VDDIOP
PB1 RXD3 USER’S PUSH BUTTON 2 PB1 as RIGHT CLICK VDDIOP
I don't have a specific answer for your board, but I can give you some pointers with the information you need.
The simplest way to solve your problem is to drop the 'interrupt handlers' requirement and simply poll the GPIO lines. You can do this from userspace, so long as you're root. Many development environments supply a kernel module to do this for you, exposing the results as an entry in /dev or /proc.
If you're going to handle interrupts, you need to write a Linux device driver. The best place to start here is the awesome Linux Device Drivers book, downloadable at http://lwn.net/Kernel/LDD3/
A GPIO driver is very simple and will mostly consist of a call to register_irq() and your userspace interface code. The userspace interface code will be much larger than the rest of the code and also cause you the most headaches.
I don't have any experience with the specific board and buildroot, but it might be interesting to look into gpio.txt in the Documentation dir inside the kernel tree. There's some explanation on how to use GPIO from userspace using sysfs.
Related
Why does any of the following register writes cause my program to halt?
slcr.DDR_CLK_CTRL[DDR_2XCLKACT] = 0
slcr.DDR_CLK_CTRL[DDR_3XCLKACT] = 0
slcr.DDR_PLL_CTRL[PLL_BYPASS_FORCE] = 1
slcr.DDR_PLL_CTRL[PLL_PWRDWN] = 1
I'm new with embedded development and I'm trying to implement some bare bones C code to put the zynq 7000 into sleep mode per page 674 of the Technical Reference Manual
All of the sleep mode steps execute without issue except for the steps listed, all of which relate to DDR, and all of which halt execution. Leaving the DDR steps out the code functions but I'm not sure I'm reaching the lowest power state.
I'm using the on-board button of my Cora Z7-07S development board as an interrupt source. The handler for the interrupt on button-down executes the power down function and executes the wake function on button-up.
I followed this tutorial (video here) on my Cora Z7-07S to get the interrupt functioning. Does using the AXI GPIOs as an interrupt source create some dependence on DDR? Is there a way to setup the PL to avoid this and still allow a GPIO interrupt?
I have developed a custom STM32L475 board with one GPIO pin wired up for synchronization along some other circuitry for the synchronization, unfortunately we decided to route the generated sinus signal from module to module.
This is not optimal so I want to optimize so it is not the sinus signal which is routed from master module to slave modules, but to just transfer a digital trigger to restart the generation of a full sine wave.
To do this I need to be able to setup the MCU's to use the one GPIO pin on each MCU as both output and trigger for a timer.
To do this without an update of the HW I need to be able to combine:
1. Using the 3 pins (one from each MCU) as open drain outputs as an AND gate, this works.
2. I know the GPIO pin can be used as external trigger, triggering on a negative edge.
The question is, is it possible to trig a timer of an output pin using only one GPIO pin, to make the MCU which finalizes its sine generation first trigger itself and the other MCU's, and if so, how?
Please note, it must use the level of the output pin itself, eventhough it is an outputpin.
I am a HW developer, learning to do firmware for our HW, so I am kind of new to software development, so I am using HAL, please be nice
STM32L475 allows to configure a GPIO in different modes that must be (exclusively) selected through the corresponding GPIOx_MODER register:1
(Digital) Input mode
General purpose output mode
Alternate function mode
Analog mode
The alternate function applied in Alternate function mode must also be selected exclusively, through the corresponding GPIOx_AFRL or GPIOx_AFRH register, resp.2
The trigger for an interrupt or timer is an alternate function, and the output of a (analogue or digital) signal is a (different) alternate function, too.
Therefore, I think there is no solution to the given problem based on peripheral configuration.
1
Reference Manual, Rev 7:
See
Section 8.5.1 for GPIO mode selection
Figures 23/24 in Section 8.4 for explanation
2
ibid.:
See
Section 8.5.9 for GPIO alternate function selection
Section 8.4.2 for explanation
I'm using an ATMega128 micro and have all of my pin inits set to output and set to low under my main section of code:
PORTB=0x00;
DDRB=0xFF;
However on startup, the output associated with PORTB.0 flicks high for a split second (I've caught it on the scope) and it seems the other outputs are doing the same. Seems like it goes LOW-HIGH-LOW. I've done some reading that it could be caused by the tri-state to output switch during startup, so I've set the PUD register to 1 before the pin inits and then back to 0 after and still no luck. Does anyone have any other ideas to keep that output off during startup? It doesn't always occur either which is what has me stumped.
The fundamental problem is a hardware issue - lack of a pull-down resistor on the GPIO so that it is floating when in the reset-default high-impedance input state.
The best you can do in software is to initialise the GPIO at the earliest opportunity immediately after the reset. To do this in CodeVisionAVR you need to use a customised startup.asm in your project as described in section 4.18 of the CoadeVisionAVR compiler manual:
...
Where I suggest you initialise PORTB and DDRB as follows:
LDI R16, 0x00
OUT PORTB, R16
LDI R16, 0xFF
OUT DDRB, R16
immediately before step 2, i.e. the first four instructions. The amount of time the GPIO will be left floating will possibly be too small for the relay to react if it is a mechanical relay. You may still have a problem for a solid state relay. The length of any pulse may depend on the power-supply rise time; if it is slow, you may get a longer pulse.
I'm trying to hijack the Timer interrupt. A colleague told me that interrupt 0x08 on the IDT (Interrupt Descriptor Table) is the timer. Of curse I checked and saw two possible answers: this which says that 8 is the real clock timer and this saying it's the Double Fault interrupt - I decided to believe him and not waste time on checking further. After finally having control over the IDT and replacing interrupt 8, nothing is happening.
So what is going on?
Did this interrupt change its purpose over time from timer to double fault?
Does this interrupt has different purposes on ARM/Intel/etc.?
My code is a kernel module, that hijacks the interrupt 8 and simply do a printk command every time the interrupt arrives. I ran it for about 25 minutes - No output in dmesg.
In case it matters: I run Linux Mint with kernel 3.8 on a VM. The host has an Intel i5.
You can find which interrupt is for timer by using this command: cat /proc/interrupt
Following is a sample output on a 6 core machine:
cat /proc/interrupts | egrep "timer|rtc"
0: 320745126 0 0 0 0 0 IO-APIC-edge timer
8: 1 0 0 0 0 0 IO-APIC-edge rtc0
LOC: 115447297 304097630 194770704 212244137 63864376 69243268 Local timer interrupts
Note, timer and rtc are different. Also there is only one rtc interrupt so far. (Lots of timer interrupts). Following is the uptime output.
uptime
14:14:20 up 13 days, 3:58, 9 users, load average: 0.47, 1.68, 1.38
I think you should check this before you hack IDT. Also, probably, you want to hack interrupt 0, not 8.
You have found two descriptions for the same IRQ because in protected mode the address range 0x0 - 0x1F are reserved for internal cpu interruptions use.
You have to remap IRQs to another address space without conflicts, in this article you can find it explained with all the source code needed:
https://alfaexploit.com/readArticle/416
I knew there is a similar post:
Steps to make a LED blink from a C/C++ program?
But now I am working on a arm-based development board, and it seems to have two serial ports that I could use it to make a LED on or off.
Basically I think the flow is , make one pin in serial "1" or on and the LED will be turned on and "0" to make it off.
Is there some reference code in C-language I could refers?
Generally speaking, the board should come with some Board Support Package (BSP) which lets you control the built in I/O. Look for a serial library if you really want to use the Hardware flow control signals.
I'd recommend looking for some GPIO (General Purpose I/O, or digial I/O) on the board, which typically lets you configure it as an input or an output. You should be able to connect the LED via a current limiting resister between a digital I/O line and a ground pin. Make sure you have the LED oriented correctly if you connect it backwards it will block the current instead lighting. And as always make sure you check it out with a digital voltage meter before connecting it.
Even if you don't have a BSP for digital I/O the configuration is usually pretty simple.
Set a bit in a register to enable it, set bit in another register to select input or output they will normally be arranged in 8-bit "ports." Some systems allow you configure individual I/O pins, other will only allow you to configure the whole port for input or output. Then you just write a 1 or 0 to the bit you want to control in an write/output register.
ARM chips typically have a considerable amount of built in peripherals today, so most boards will just be bringing the I/O out to physical connectors on the board and you may need to read the chip vender's documentation to find the register memory map. Better board venders will supply documentation, a library (BSP) and examples. Luminary Micro even supplies chips with built in ethernet MACs and PHYs, just add a connector and Magnetics and you have a 1 chip Webserver.
This will, I'm afraid, be heavily dependent on the specifications of the particular arm-based development board you are using.
You need to find documentation specific to that board.
I used to do this kind of programming before.
You need to study the serial port connection
http://www.lammertbies.nl/comm/cable/RS-232.html
http://www.beyondlogic.org/serial/serial.htm
It has +5v, -5v on the output, I can't remember clearly now. Not every pin is needed.
I never use ARM before, but I use a 8-bit PIC controller to program it. I guess you can find a lot of example online.
The preferred alternative for controlling a GPIO is via a BSP. Because this BSP (board support package) does all the work for you in setting all peripherals to good defaults and and allowing you to call a function. Possibly your BSP of choice will have a function to write a byte to an 8-bit GPIO port; your LED will only have one bit. In this case your C code could look like: (at least: it will work like this on Luminary Micro kits). (Example code; requires a bit of extra work to make it compile especially on your kit).
/* each LED is addressed by an address (byte) and a bit-within-this-byte */
struct {
address, // address of IO register for LED port
bit // bit of LED
} LEDConfigPair;
struct LEDConfigPair LEDConfig[NUMBER_OF_LEDS] = {
{GPIO_PORTB_BASE,0}, // LED_0 is at port B0
{GPIO_PORTB_BASE,1} // LED_1 is at port B1
} ;
/* function LED_init configures the GPIOs where LEDs are connected as output */
led_init(void)
{
U32 i;
for(i=0;i<NUMBER_OF_LEDS;i++)
{
GPIODirModeSet( LEDConfig[i][0], LEDConfig[i][1], GPIO_DIR_MODE_OUT );
}
}
/* my LED function
set_led_state makes use of the BSP of Luminary Micro to access a GPIO function
Implementation: this BSP requires setting 8 port wide IO, so the function will calculate a mask (
*/
set_led_state(U8 led,bool state)
{
U8 andmask;
U8 setmask;
andmask = ~(1 << LEDConfig[led].bit);// a bitmask with all 1's except bit of LED
if (true == state)
{
setmask = (1 << LEDConfig[led].bit); // set bit for LED
} else
{
setmask = 0;
}
GPIOPinWrite(LEDConfig[led].address, andmask, setmask);
}
Of course this is all spelled out; it can be done in a single lines like this:
#DEFINE SETLEDSTATE(led,state) GPIOPinWrite(LEDConfig[led].address, ~(1<<LEDConfig[led].bit),(state<<LEDConfig[led].bit))
this will do the same, but only makes sense when you can dream bit masks, and you only want to toggle some LEDs to debug the real program...
The alternative: bare metal.
In this case you need to set up everything for yourself. For an embedded system, you need to be aware of pin multiplexing and power management (assuming memory controller and cpu clocks are already set up!)
initialization: set pin multiplexing in such a way that the function you want to control is actually mapped on the package.
initialization of pheripheral (in this case either a UART, or a GPIO function on the same pin)
You can't do it using Rx or Tx pins of Serial port. For that you just need to control the RTS or CTS pins of serial port.
Just google for "access COM port in VC++ code" and then control the RTS and CTS status pins to turn ON and OFF any external device.