How can I use C macros to define PIC microcontroller pin names? - c

PIC microcontrollers have 3 basic registers to set GPIO (General Purpose I/O) pin status. These are:
TRIS (Tri-status, the direction register. Sets the pin as in or out)
PORT (The input buffer)
LAT (Latch, the output burffer).
Ports can be A, B, C... etc.
So the TRIS register for the port A is TRISA.
Then finally there is the pin number. For example, TRISA1.
TRISA1 is defined as:
// TRISA<TRISA1>
extern volatile __bit TRISA1 __at(0x461); // # (0x8C * 8 + 1)
#define TRISA1_bit BANKMASK(TRISA), 1
I would like to define a macro to easily name the pins as:
#define _DATA_OUTPUT A2
So I can do code like:
LAT_DATA_OUTPUT = 1;
PORT_DATA_OUTPUT = 0;
and have it converted by the preprocessor to:
LATA2 = 1;
PORTA2 = 0;
so I can later expand to other pin registers such as ANSEL, WPU, etc, without rewriting the macros or add special cases.
Is this possible? Or what's the closest thing I can do to emulate this?

You can do that by create macro like that:
#define _DATA_OUTPUT A2
#define LAT_DATA(X) LAT##X
#define LAT_DATA_OUTPUT LAT_DATA(_DATA_OUTPUT)
#define PORT_DATA(X) PORT##X
#define PORT_DATA_OUTPUT PORT_DATA(_DATA_OUTPUT)
you can use it as example .

You can already do this. You haven't noted your PIC model or your IDE version or what toolchain you are using, but assuming you're on MPLAB X with an XC compiler this functionality is already there. Make sure you're including <xc.h> and it should read what chip you have from the project configuration and have the macros already made for you.
You can then set entire registers (using TRISA as an example):
TRISA = 0x0000; //All A pins outputs
Or set individual pins in that register:
TRISAbits.TRISA0 = 0;
TRISAbits.TRISA8 = 0;
You could also define your own macros:
#define TRISA0 TRISAbits.TRISA0
#define SET_TRISA0_IN TRISAbits.TRISA0 = 1

Related

Atmel C Pin Manipulation Macros

So I have been programming in Atmel C for a while and I have gotten used to all the C bit manipulation, so now I want to hide it. I want to hide the bit manipulation not only to make my code more readable but also make it easier to maintain and modify in case our hardware changes or we make new hardware.
So I am asking you what are the best macros for Atmel C for basic pin manipulation.
The features I am looking for are:
Set a Pin to be Input or Output
Set an Output Pin HIGH or LOW
Read the Value of an Input Pin
So I have found a few macros that I could use but none really fit my bill.
Links:
http://www.piconomic.co.za/fwlib/group___a_v_r___p_i_o.html (still have to keep multiple defines per pin)
http://www.starlino.com/port_macro.html (doesn't compile, AVR Studio 6.2)
Changing a global variable in C (best one, near the top of the question under "/* LCD DEFINES */"
What I would really like is something like this:
#define LED1 PA1
#define BUTTON1 PB0
set_output(LED1);
output_high(LED1);
delay_ms(100);
output_low(LED1);
set_input(BUTTON1);
uint8_t tmpVal = get_input(BUTTON1);
if( tmpVal == 1 )
{
// assuming button IS pressed here
}
else
{
// assuming button IS NOT pressed here
}
Any ideas on the cleanest way to do this?
I could handle keeping around a few more defines per pin but I feel like that shouldn't be needed. Shouldn't PA1 and PB0 be able to tell us everything or do they get defined into a single value?
EDIT: Using Atmel Studio 6.2 on Windows
Thanks,
Rob R.
Nevermind this does compile
http://www.starlino.com/port_macro.html
// MACROS FOR EASY PIN HANDLING FOR ATMEL GCC-AVR
//these macros are used indirectly by other macros , mainly for string concatination
#define _SET(type,name,bit) type ## name |= _BV(bit)
#define _CLEAR(type,name,bit) type ## name &= ~ _BV(bit)
#define _TOGGLE(type,name,bit) type ## name ^= _BV(bit)
#define _GET(type,name,bit) ((type ## name >> bit) & 1)
#define _PUT(type,name,bit,value) type ## name = ( type ## name & ( ~ _BV(bit)) ) | ( ( 1 & (unsigned char)value ) << bit )
//these macros are used by end user
#define OUTPUT(pin) _SET(DDR,pin)
#define INPUT(pin) _CLEAR(DDR,pin)
#define HIGH(pin) _SET(PORT,pin)
#define LOW(pin) _CLEAR(PORT,pin)
#define TOGGLE(pin) _TOGGLE(PORT,pin)
#define READ(pin) _GET(PIN,pin)
/*
BASIC STAMPS STYLE COMMANDS FOR ATMEL GCC-AVR
Usage Example:
———————————————–
#define pinLed B,5 //define pins like this
OUTPUT(pinLed); //typo fixed
//OUTPUT(pinLED); //compiles as DDRB |= (1<<5);
HIGH(pinLed); //compiles as PORTB |= (1<<5);
———————————————–
*/
There is just one typo which I have fixed

C preproc: pasting valid token and value of a token

I am working with an STM32F1 microcontroller, for which a header is provided that defines bit masks and values for registers as follows:
#define RCC_CFGR_PLLMULL //Mask of PLL multiplier setting bits
#define RCC_CFGR_PLLMULL1 //Value of PLL multiplier bits for PLL x1
#define RCC_CFGR_PLLMULL2 //Value of PLL multiplier bits for PLL x2
#define RCC_CFGR_PLLMULL3 //Value of PLL multiplier bits for PLL x3
etc etc.
What I want to do is define my PLL multiplier as an integer so I can use it to derive the clock value - ie PLLCLK = IN_CLK * PLL_MULT - and paste the value onto RCC_CFGR_PLLMULL to obtain the correct setting bits. The macros I would normally use for this are as follows:
#define APPEND_VAL_HELPER(A, B) A##B
#define APPEND_VAL(A, B) APPEND_VAL_HELPER(A,B)
Then if I define SOME_NUM as, say, 123:
#define FOO APPEND_VAL(BAR, SOME_NUM)
Results in the FOO defining as BAR123. Normally this works. Here's the problem: in this case, RCC_CFGR_PLLMULL is a valid token before being pasted. This results in it expanding in the invocation of APPEND_VAL and I get something like ((uint32_t)0x003C0000)123. I can't figure out how to get B to expand without also expanding A, at least in GCC. There are workarounds to this but I'm looking for a clean solution. Does it exist?
I'm not sure what you would consider a "clean" solution, but this works for me and doesn't seem too bad:
/* target header */
#define RCC_CFGR_PLLMULL 0x003C
#define RCC_CFGR_PLLMULL1 0x0003
/* pasting macros */
#define APPEND_VAL_HELPER(A, B) A ## B
#define APPEND_VAL(A, B) APPEND_VAL_HELPER(A, B)
#define RCC_CFGR(T, N) APPEND_VAL(RCC_CFGR_, APPEND_VAL(T, N))
You use that as, for example,
#define FOO RCC_CFGR(PLLMUL, 1)
You can also do
#define BAR RCC_CFGR(PLLMUL, )
to define BAR to RCC_CFGR_PLLMUL (no tail).
Obviously, this is specific to a subset of possible target macros, but it does the job and reads cleanly. To the best of my knowledge there is no way to write a fully general token-pasting macro -- those that are most general suffer from issues such as the one you described.

Is there a compiler directive to replace part of a constant

I'm working with embedded C for a microcontroller right now and I find that sometimes there are several peripherals that differ only by a single letter (for example UARTA, UARTB, etc). The code for each peripheral is often times identical except for lettering of otherwise identical registers. For example to setup peripheral A I would do something like:
UCA2CTL1 |= UCSWRST; // Put state machine in reset
UCA2CTL0 |= UCSYNC+UCCKPL+UCMSB; // 3-pin, 8-bit SPI slave
// Continue initializing peripheral registers with "A" in name
And to setup peripheral B I have exactly the same code, except that the register names are transposed by 1 letter:
UCB2CTL1 |= UCSWRST; // Put state machine in reset
UCB2CTL0 |= UCSYNC+UCCKPL+UCMSB; // 3-pin, 8-bit SPI slave
// Continue initializing peripheral registers with "B" in name
I would like to have the ability to change which peripheral I target without having to #ifdef/copy/paste code or find/replace. Is there some compiler directive or clever trick that can implement this behavior so that I only have to write the code once? I would love to just #define the last letter in the peripheral, but something like that seems to wander dangerously close to code stink to me.
Will this work for you?
#define INITUC(device) \
UC ## device ## 2CTL1 |= UCSWRST; \
UC ## device ## 2CTL0 |= UCSYNC+UCCKPL+UCMSB
...
INITUC(A);
INITUC(B);
Assuming those constants are const and not defines You can do something like that:
#define MAKECONST(X) const int X ## 1; \
const int X ## 0; \
X ## 1 |= UCSWRST; \
X ## 0 |= UCSYNC+UCCKPL+UCMSB;
And then:
MAKECONST(UCA2CTL)
MAKECONST(UCB2CTL)
Note that my example includes declaration, which I don't know if you need, if not, omit first two lines of the define. E.g.:
#define SETUP(X) X ## 1 |= UCSWRST; \
X ## 0 |= UCSYNC+UCCKPL+UCMSB;

LUT in a macro C

I am currently working on setting up a framework in C for usage between several microcontrollers.
The framework has to carry all device specific code, so the application only contains the abstract usage of peripherals (like SerialPort_Read, write, SetBaudRate, etc etc.)
One of the things I am struggling with to find a solution for in C are the I/O pin map. I've seen projects (like the very very popular Arduino) where the pin map is putten in a LUT (look up table) which is used during runtime. However, this LUT will never be modified during runtime, so there is no use to have this in the memory.
For example, this function resolves some bit indexes and registers from some 'const uint' tables, and either sets or clears a bit:
void pinMode(uint8_t pin, uint8_t mode)
{
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *reg;
if (port == NOT_A_PIN) return;
// JWS: can I let the optimizer do this?
reg = portModeRegister(port);
if (mode == INPUT) {
uint8_t oldSREG = SREG;
cli();
*reg &= ~bit;
SREG = oldSREG;
} else {
uint8_t oldSREG = SREG;
cli();
*reg |= bit;
SREG = oldSREG;
}
}
Because this is actual C code running on the controller it's draining effiency and speed. I'd rather define some sort of macro that does the same thing, but is already resolved during compilation to a 'one-liner' that can be compiled much more efficiently:
GPIO_Write(PORTA, 5, 1); // Write '1' to pin 5 on PORTA
> LATA |= 1<<5; // Sets bit 5 high
GPIO_Tris(PORTA, 4, OUTPUT); // Set pin 4 on PORTA to output
> PORTA &= ~(1<<4); // sets pin 4 as output I/O type
Does anyone know if it's possible (and how) to define and use a look-up table with a macro in C?
At this moment I am using the MicroChip C30 compiler, which I believe is based in GCC. It's supposed to be portable between different compilers, including MicroChip C18, C32 and in further also ARM and AVR.
For your specific example, something along these lines will work:
#define WRITE_PORTA LATA
#define GPIO_Write(port, pin, value) \
(value ? WRITE_##port |= (1U << (pin)) \
: WRITE_##port &= ~(1U << (pin)))
#define INPUT 0
#define OUTPUT 1
#define GPIO_Tris(port, pin, direction) \
((direction) == INPUT ? port |= (1U << (pin)) \
: port &= ~(1U << (pin)))
You'll have to make sure to define LATA and PORTA in a way the system will understand - in particular trying to overload its meaning the way it seems to be in your example might be hard to resolve.
Which processor or microcontroller are you targeting?
You might be underestimating the usefulness of the LUT.
For many processors, the LUT does more than map a 'logical' pin number to a single value, the 'physical' pin number. The LUT maps the 'logical' pin number to several pieces of information.
In general, the 'logical' pin is mapped to the port address of the appropriate read/input or write/output register, and the bit offset within the read or write register. So the pin value, on many MCU's, is really mapped to a struct. It might also include a mapping to the data direction register and fields within it, as well as registers which set the state of pull-up or pull-down resistors.
For example, I have code to multiplex a 8x8 display. At run-time, I need to use pinMode to turn a pin from an output to a high impedance input, and so that information needs to be encoded somehow.
It is possible to do this sort of thing, with some ingenuity, on some MCU's.
ARM MCU's (and I believe 8051, though I've never used one) using 'bit band addressing' http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0179b/CHDJHIDF.html
This assigns a unique memory address for each port pin, and fixed offsets can derive the address of the pin for the other data register, and other functions. This is not magic, the code encodes the information that is often stored in the LUT.
For other MCU's, they really do need both port and bit position, so it is two values for each pin number.
If you are willing to ditch the idea of using integers for pins, and instead use names, like P0, P1, then you could initialise a lot of const struct's, one per pin name, and your functions would take the const struct values. The struct would contain the initialised port and bit offset or bit mask values. The compiler may be able to optimise for speed. This would avoid having a LUT, but would still use similar amounts of space for pins that are used. You might be able to arrange it so that unused pins would not need to be included in the code, and hence saving space.
Edit: If you are willing to use C++, I'd suggest C++ templates which can give a much better solution than macros. They can be type safe, and are often easier to debug (if you have hardware debugging, e.g. JTAG and gdb)
Consider the following macro:
#define write(port, pin, value) do { \
if (value) \
LAT##port |= 1 << pin; \
else \
LAT##port &= ~(1 << pin); \
} while (0)
Usage:
write(A, 3, 1); // compiles to LATA |= 1 << 3;
write(B, 2, 0); // compiles to LATB &= ~(1 << 2);
Is that the kind of thing you were after?
I've seen it done (https://github.com/triffid/Teacup_Firmware/blob/Gen7/arduino.h) with a couple macros:
/// Read a pin
#define _READ(IO) (IO ## _RPORT & MASK(IO ## _PIN))
/// write to a pin
#define _WRITE(IO, v) do { if (v) { IO ## _WPORT |= MASK(IO ## _PIN); } else { IO ## _WPORT &= ~MASK(IO ## _PIN); }; } while (0)
/// set pin as input
#define _SET_INPUT(IO) do { IO ## _DDR &= ~MASK(IO ## _PIN); } while (0)
/// set pin as output
#define _SET_OUTPUT(IO) do { IO ## _DDR |= MASK(IO ## _PIN); } while (0)
// why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
/// Read a pin wrapper
#define READ(IO) _READ(IO)
/// Write to a pin wrapper
#define WRITE(IO, v) _WRITE(IO, v)
/// set pin as input wrapper
#define SET_INPUT(IO) _SET_INPUT(IO)
/// set pin as output wrapper
#define SET_OUTPUT(IO) _SET_OUTPUT(IO)
with:
#define DIO0_PIN PIND0
#define DIO0_RPORT PIND
#define DIO0_WPORT PORTD
#define DIO0_PWM &OCR0B
#define DIO0_DDR DDRD
#define DIO1_PIN PIND1
#define DIO1_RPORT PIND
#define DIO1_WPORT PORTD
#define DIO1_PWM &OCR2B
#define DIO1_DDR DDRD
...
You could modify the macros to take straight integers rather than DIOn

#define PORTX.x in Avr Studio 5 (ATmega16)

I'm writing a new and special library whith new algorithms and abilities for KS0108 GLCD Driver. I'm using ATMega16. My dot matrix GLCD dimension is 128x64.
How can I use #define code to define different port pins?
for example: #define GLCD_CTRL_RESTART PORTC.0
IDE: AVR Studio 5
Language: C
Module: 128x64 dot matrix GLCD
Driver: KS0108
Microcontroller: ATMega16
Please explain which headers I should use? and also write a full and very simple code for ATMEga16.
In ATmega, pin values are assembled in PORT registers. A pin value is the value of a bit in a PORT. ATmega doesn't have a bit addressable IO memory like some other processors have, so you cannot refer to a pin for reading and writing with a single #define like you suggest.
What you can do instead, if it helps you, is to define macros to read or write the pin value. You can change the name of the macros to suit your needs.
#include <avr/io.h>
#define PORTC_BIT0_READ() ((PORTC & _BV(PC0)) >> PC0)
#define WRITE_PORTC_BIT0(x) (PORTC = (PORTC & ~_BV(PC0)) | ((x) << PC0))
uint8_t a = 1, b;
/* Change bit 0 of PORTC to 1 */
WRITE_PORTC_BIT0(a);
/* Read bit 0 of PORTC in b */
b = PORTC_BIT0_READ();
thanks a lot, but i found this answer in AVR Freaks at here:
BV=Bit Value.
If you want to change the state of bit 6 in a byte you can use _BV(6) which is is equivalent to 0x40. But a lot us prefer the completely STANDARD method and simply write (1<<6) for the same thing or more specifically (1<<<some_bit_name_in_position_6)
For example if I want to set bit 6 in PORTB I'd use:
Code:
PORTB |= (1 << PB6);
though I guess I could use:
Code:
PORTB |= _BV(6);
or
Code:
PORTB |= _BV(PB6);
But, like I say, personally I'd steer clear of _BV() as it is non standard and non portable. After all it is simply:
Code:
#define _BV(n) (1 << n)
anyway.
Cliff

Resources