Interrupts on SAMD21 with ASF - arm

I am starting on learning programming Atmel SAMD devices using ASF, and trying to do a simple test interrupt application. I have found this source from Microchip about interrupts.
In this code snippet, it populates a configuration struct and then attaches it to the interrupt channel. Three macros, BUTTON_0_EIC_PIN, BUTTON_0_EIC_MUX and BUTTON_0_EIC_LINE, are predefined macros specific to the board. I want to attach interrupt to a regular, non-predefined pin, in such case, what the syntax would be?
void configure_extint_channel(void)
{
struct extint_chan_conf config_extint_chan;
extint_chan_get_config_defaults(&config_extint_chan);
config_extint_chan.gpio_pin = BUTTON_0_EIC_PIN;
config_extint_chan.gpio_pin_mux = BUTTON_0_EIC_MUX;
config_extint_chan.gpio_pin_pull = EXTINT_PULL_UP;
config_extint_chan.detection_criteria = EXTINT_DETECT_BOTH;
extint_chan_set_config(BUTTON_0_EIC_LINE, &config_extint_chan);
}
I cannot seem to find any sources that provides a general syntax as opposed to using predefined board pins for buttons and leds, and I couldn't find the related section on either ASF documentation or the datasheet of the device.
Say, for instance, I want to use PA18, the 18th pin of port-A, that is connected to 2nd interrupt channel, EXTINT[2], what would the corresponding terms be in place of those three macros?

After creating an example project using a known board template, and digging into an uncomfortable amount of macros expanding to other macros, I have found the actual definitions.
// v----- peripheral group A, where EIC resides
BUTTON_0_EIC_PIN --> PIN_P<X><#>A_EIC_EXTINT<#>
BUTTON_0_EIC_MUX --> MUX_P<X><#>A_EIC_EXTINT<#>
BUTTON_0_EIC_LINE --> <EXTINT channel number>
For instance PA18 connected to EXTINT2 would be:
PIN_PA18A_EIC_EXTINT2
MUX_PA18A_EIC_EXTINT2
2

Related

Where is the ISR macro's definition located for AVR microcontrollers?

I've looked through both <avr/io.h>, and <avr/iom328p.h> for a macro which defines the ISR macro, as well as the datasheet for the ATmega328P and I have yet to find anything. All I can find is external sources saying that you make an interrupt service routine by writing
ISR (/*<ISR-vector>*/)
{
/* ISR code here */
}
but I haven't found its source/definition anywhere.
The macro is defined in avr/interrupt.h, which you can view for example here (github mirror, not an official source). In case you were looking for it to understand how it works i also recommend you read about interrupt and signal function attributes here, because all that the ISR macro does is define a function with a specific attribute and name.

Embedded sensor module design - external functions

I have one small question about proper module design for embedded device (different manufacturer, cortex M0 - M7).
Lets say we have c sensor module for reading accelerometer data from I2C device acc.c and corresponding headerfile acc.h.
Module needs external functions for I2C communication. And I am thinking about correct implementation of module.
Until now I have in my mind these 3 versions:
Include I2C.h driver (This option is last option, because it will fix module usage to one platform)
Weak definition of externaly provided functions (But again weak definition of function is pretty fixed on platform - NXP has different implementation than STM etc)
Function pointers in process structure, so every device would have assigned external function for I2C communication (It seems to be little bit overkill for this kind of device and debugging of such implementation can be little bit tricky, but overall implementation seems to be clean).
Do you have any ideas for better solution which would be more readable/debuggable than function pointers and still portable?

tiva c implicit function

I am trying to build a simple logic analyzer with TM4c123 but anytime when I use the function ROM_.... it appears to be an error( implicit of function ROM_..) Anyone knows why?
for example:
ROM_FPUEnable();
ROM_FPULazyStackingEnable();
// run from crystal, 80 MHz
ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
// enable peripherals
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
// set UART pins
GPIOPinConfigure(0x00000001);
GPIOPinConfigure(0x00000401);
ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
// init PORTB
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
GPIO_PORTB_DIR_R = 0x00;
GPIO_PORTB_DEN_R = 0xff;
// configure uart
ROM_UARTConfigSetExpClk(UART0_BASE, ROM_SysCtlClockGet(), 115200,
(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
All of the function ROM are errors, why? I already include rom.h and rom_map.h
You probably didn't defined your target device.
Try to add something like -DTARGET_IS_TM4C123_RB1 to your Makefile.
This define is necessary in order for the ROM_* symbols be defined.
You are using a combination of driverlib (tivaware) and direct register modification (DRM). Use one or the other, preferably driverlib.
You should actually be using the MAP_ calls instead of ROM_. ROM_ is deprecated but still usable for testing. Don't put ROM_ in production code. I know the examples still use ROM_.
You are missing the header file for ROM anyways. If you want to use ROM_, you need to include driverlib/rom.h. That's why it's complaining about the implicit function call. Any call to a ROM_somethingsomethingdarkside() is not defined. You will also need to include stdint and stdbool, as driverlib uses those c99 types. To use the map calls, you'll need to include driverlib/rom_map.h
You may also need to include driverlib/gpio.h, driverlib/sysctrl.h. Not sure on that. I've never mixed things like you have done, and I always debug using the compiled in driverlib first, then prefixed the driverlib calls with MAP_ after I know things are working. I haven't ever gone back to remove my includes for the compiled in driverlib libraries. The toolchain seems to be smart enough to not compile them in after I stop calling them anyways. Now I kinda want to try that though.
To be clear, ROM_ or MAP_ is calling driverlib calls out of the on chip ROM.
I suspect that you are not sure what the code you are using really is and what it does by the way you're mixing DRM and driverlib libraries. I HIGHLY suggest you take the time to go through the online workshop for the Tiva C. It's a series of short videos and labs that will clear up all of this. I went intentionally neurotically slow and it took me a weekend. You can do it in a day, and it'll be a day well spent. It'll save you that many times over. It's out of date slightly as far as code composer goes, but it's still useable. I have all my students go through it before they start work on this platform.
http://processors.wiki.ti.com/index.php/Getting_Started_with_the_TIVA™_C_Series_TM4C123G_LaunchPad
Edit: yes, and as vitor points out, you also need that define as well.
I would reccommend using "driverlib/gpio.h" and "driverlib/sysctl.h"
for the Pin configuration with TM4C devices

Libopencm3 interrupt table on STM32F4

I'm using libopenCM3 for my project on STM32F4. I've used previously Standard Peripheral Library and newer Hardware Abstraction Layer developed by ST.
In these libraries you have assembly file (startup file) with the definition of vector table.
This is what I'm missing for libopenCM3. Can you please show me where to find this table? Or is it done some another way?
I really need to use interrupts in my project.
Thanks.
Can you please show me where to find this table?
Interrupt vector table is located in lib/cm3/vector.c:
__attribute__ ((section(".vectors")))
vector_table_t vector_table = {
...
.irq = {
IRQ_HANDLERS
}
};
And IRQ_HANDLERS for STM32F4 are defined in lib/stm32/f4/vector_nvic.c file. This file will be available after building the library (it's generated with irq2nvic_h script). In this file you can see something like this:
#define IRQ_HANDLERS \
[NVIC_DMA1_STREAM0_IRQ] = dma1_stream0_isr, \
[NVIC_ADC_IRQ] = adc_isr, \
...
Functions like dma1_stream0_isr() and adc_isr() are defined like this:
#pragma weak adc_isr = blocking_handler
So these functions are just blocking handlers by default. But they are defined as weak, so you can easily redefine them in your code.
Or is it done some another way?
As discussed above, it boils down to next: you just need to define interrupt handler function (ISR) with correct name in your code, and your function will be placed to interrupt vector table automatically.
For instance, if you want to handle UART2 interrupt, just implement usart2_isr() function somewhere in your code. For the whole list of ISR function names refer to include/libopencm3/stm32/f4/nvic.h. But those names are usually pretty straight-forward.
Also, check out the libopencm3-examples project. The chances are you will find just what you need there.

ARM NXP LPC2378: Is is safe to modify GPIO pin output state via register access?

I'm currently using the ARM NXP LPC2378 for a project using the IAR compiler. I'm modifying the GPIO output pins through a somewhat nonstandard method. Here is my code below:
void SetPinhigh(int port_number, int pin_number)
{
volatile unsigned long* set_register = (volatile unsigned long *)(BASE_ADDR + (PIN_PORT_LENGTH_IN_BYTES*port_number) + PIN_SET_REGISTER_OFFSET);
*set_register |= (1 << pin_number);
}
Is this a safe method to use? If I step through the code, IAR gives me warnings about writing to non RAM regions, but I'm writing to the register location and the pins are toggling. I like this method because it seems cleaner to use than the structures that IAR has created. Is there a better method other people know of?
IAR is right, registers are not RAM. :) It is possibly best to look how to suppress warnings looking inside examples coming with IAR (if there any). There mey be IAR's custom keyword or pragma, thich tells compiler how you're intended to do.
It may also be issue in memory map, as there may need to define register region somehow.
I'm working with GCC and ARM, and it does not complain on any method to access registers. I used:
direct and calculated address (*((volatile unsigned int *)0xNNNNNNNNU) |= 1<<pin);
arrays, structs, unions and bitfields by direct address (through it is dangerous, but it makes code looking so nice);
symbols defined in map file with all above (this may be mostly C compliant because of dealing with linker, not compiler).
There is proposed new extension pretending to be a standard I found recently, called TR 18037: Embedded C. Section "6 BASIC I/O HARDWARE ADDRESSING" give common method to access hardware (cite from pdf):
#include <iohw.h>
#include "iodriv_hw.h" /* Platform-specific designator
definitions. */
// Wait until controller is no longer busy.
while (iord(dev_status) & STATUS_BUSY) /* do nothing */;
// Write value to controller.
iowr(dev_out, ch);
There are also ioand, ioor function[ like macro]s and many others.
Example implementation for iohw.h is also there so you may add support for this to IAR on your own.
I suggest that you look in the toolchain's device specific header file to see how SFR's are declared. You could also read the advice on page 142 The IAR C/C++ Development Guide and also IAR's Writing Device Header Files guide.
Specifically you may want to either use the __IO_REGxx macros are defined or at least look at how they are defined in io_macros.h
Is this the compiler or the debugger that's giving you warnings about writing to non-RAM locations?
I'd be surprised if the compiler gave a warning about writing to non-RAM for the code you posted - it doesn't seem possible for the compiler to determine what the address will end up being since it depends on the port_number parameter.
You may need to configure the debugger for your device. IAR has a device description file for the LPC2378 in "C:\Program Files\IAR Systems\Embedded Workbench 5.0\ARM\config\debugger\NXP\iolpc2378.ddf" that lets the debugger know what registers are at what addresses. This configuration file lets the debugger show you the registers broken down by the bitfields with names matching (or closely matching) the names used in the device docs when you use the "Register" view window in the debugger.
If you select the right device in the project property page "General Options/Target" tab then the correct .ddf file should be configured automatically. If that's not working for some reason or you need a custom file, you can point to the right file in the project property "Debugger/Setup/Device description file" entry.
Using the right .ddf file (or correcting it if it's not right) might also prevent the warnings you see if they're coming from the debugger.
Looks great to me. I do it in the same way on other processors/toolschains, memory mapped registers behaves the same as RAM. I do not know how your processor and compiler works and if could have issues but can not see how that could be a problem unless the compiler tries to be clever. I would find a way to suppress the warning.
Accessing memory and accessing memory-mapped registers are mostly the same. There may be limitations on how memory-mapped registers are accessed, however. On the LPC2378, only 32-bit accesses are allowed:
All peripheral register addresses are word aligned (to 32 bit boundaries) regardless of their size. This eliminates the need for byte lane mapping hardware that would be required to allow byte (8 bit) or half-word (16 bit) accesses to occur at smaller boundaries. An implication of this is that word and half-word registers must be accessed all at once. For example, it is not possible to read or write the upper byte of a word register separately.
(The LPC2378 manual http://www.keil.com/dd/docs/datashts/philips/lpc23xx_um.pdf)
As you use unsigned long for accessing the register, you should be ok. As a matter of style, you could also declare a struct with the GPIO registers and access the register like this:
gpio_port_registers_t *port = (gpio_port_registers_t *)BASE_ADDR;
port[port_number]->set_register |= (1 << pin_number);

Resources