-
Content Count
908 -
Joined
-
Last visited
-
Days Won
85
Reputation Activity
-
chicken got a reaction from omerdf in Generate 1 pulse per second using MSP430
Welcome to the forum.
RST and TEST are the connections to program and debug your MCU. If you haven't already, get a MSP430FET or a newer MSP430 LaunchPad (e.g. MSP430F5529LP). This is required to load your application into the MCU. Also see http://43oh.com/2011/11/tutorial-to-use-your-launchpad-as-a-programmer/
There can only be one interrupt service routine (ISR) for a given interrupt vector (e.g. TIMER0_D0_VECTOR in your code). And I don't think you can declare an ISR within another function. Move the ISR to the end of your code, outside of main. If the ISR needs to do different things depending on certain conditions, you need to handle that within one ISR using some state flags.
It also looks like the configuration of Timer D0 is only halfway done. You will have to look at the datasheet and family user's guide to learn more about how to configure the peripherals of your MCU. The product page on ti.com is a good start to find relevant documentation:
http://www.ti.com/product/MSP430F5131
-
chicken got a reaction from Fmilburn in MSP430 Wearable with Radio
What is the role of the radio communication?
If it's about synchronization, you could take an idea from Disney and go with IR.
http://www.theverge.com/2012/8/13/3239390/disney-glow-with-the-show-led-ears
http://www.stuffandymakes.com/blog/2012/07/08/disney-glow-with-the-show-ears-teardown
MSP430 inside, but also three AAA batteries.
-
chicken got a reaction from omerdf in Generate 1 pulse per second using MSP430
PS: You may want to start with a basic tutorial on timer interrupts. E.g.
https://www.embeddedrelated.com/showarticle/182.php
-
chicken got a reaction from energia in SPI between MSP430/432 and MCP3911
You will need to connect with DGND / GNDB.
GND is the reference point to decide whether a signal is high or low. In electronics, connected GND is almost always required/assumed with only a few exceptions.
Did you also check SS with the oscilloscope?
Typically, SPI does not require pull-ups/downs. Unless explicitly mentioned in the datasheet of the MCP3911 or related evaluation boards, you probably don't need them.
-
-
chicken got a reaction from yyrkoon in More C versus C++
Kate Gregory's point wasn't that you should stop using C. The talk was about better approaches to teach people C++ that don't know C and may even be new to programming. For that audience, starting with higher level concepts rather than pointers and char arrays makes a lot of sense.
Getting a const char* out of a string should be straight forward. In the days of classes (when I was doing large scale C++ projects), the string class usually had an operator that transparently took care of the conversion. Not sure if STL has the same (I think so) or whether you explicitly have to use c_str() method.
That being said, simply stick to the C++ constructs that make your live easier and don't feel bad about mixing them with plain C. I like to use classes to build better abstractions, or the template library for solid container constructs like lists. No benefit in being a purist in any direction.
-
chicken got a reaction from StrangerM in [POTM] dAISy - A Simple AIS Receiver
@@StrangerM just tried with a MSP430F5529 LaunchPad and it works for me.
I tried both ways entering the bootloader, either pressing the BSL button when plugging in or the B command in the debug menu.
I can see two potential issues:
1) Make sure your firmware file is not corrupted. Some browsers seem to save HTML code instead of plain text when downloading a .txt from Github. I just uploaded them to Github as ZIP file to avoid that issue.
2) On my LaunchPad, only the GND, 5V and 3.3V jumpers are in. The other jumpers on the debug connection are empty.
Regards,
Adrian
-
chicken reacted to LiviuM in MSP432 with WS2811 LED strip, where to start?
Hi Bob,
If there it is a current flowing through the resistor (to be throttled), then Vin != Vout (Vin = Vout + I*R).
A resistor (+ the ESD protection diode) can be seen as the simplest "level adapting" structure, if the resistor is large enough to keep the current in the Pin's specification.
As for the actual case, with a 3.3V output driving a 5V CMOS input, as the input is practically floating, I don't see any reason for a damage to the output.
In the worst case, the 3.3V wouldn't be enough to switch the input, if it is a Schmitt trigger input, for example (the most Schmitt triggers I know have VIH = 0.7*VDD => VIH = 3.5V @VDD = 5V).
My 2 (euro) cents, of course.
Best regards,
Liviu
-
chicken got a reaction from Fmilburn in Basic MSP430 GPIO Macros
In my project, I use a few basic macros for GPIO. The goal is, that I can easily redefine pin assignment in a central location without compromising performance or code size.
The macros (gpiomacros.h):
// MSP430 gpio macros #define GPIO_SEL(port) P ## port ## SEL #define GPIO_DIR(port) P ## port ## DIR #define GPIO_OUT(port) P ## port ## OUT #define GPIO_IN(port) P ## port ## IN #define GPIO_IS_INPUT(port,pin) { GPIO_SEL(port) &= ~(pin); GPIO_DIR(port) &= ~(pin); } #define GPIO_IS_OUTPUT(port,pin) { GPIO_SEL(port) &= ~(pin); GPIO_DIR(port) |= (pin); } #define GPIO_IS_PERIPHERAL_IN(port,pin) { GPIO_SEL(port) |= (pin); GPIO_DIR(port) &= ~(pin); } #define GPIO_IS_PERIPHERAL_OUT(port,pin) { GPIO_SEL(port) |= (pin); GPIO_DIR(port) |= (pin); } #define GPIO_SET(port,pin) { GPIO_OUT(port) |= (pin); } #define GPIO_CLEAR(port,pin) { GPIO_OUT(port) &= ~(pin); } #define GPIO_READ(port,pin) ( GPIO_IN(port) & (pin) ) In a central configuration file (e.g. hardware.h) I assign pins like this:
// Pin assignment #define LED1_PIN BIT1 #define LED1_PORT 6 #define LED2_PIN BIT0 #define LED2_PORT 1 And then in the code I interact with GPIO like this:
// Setup LEDs GPIO_IS_OUTPUT(LED1_PORT, LED1_PIN); GPIO_IS_OUTPUT(LED2_PORT, LED2_PIN); // Turn off LEDs GPIO_CLEAR(LED1_PORT, LED1_PIN); GPIO_CLEAR(LED2_PORT, LED2_PIN); The macros are resolved in two steps:
1. Higher level "functions" define the commands. E.g. GPIO_SET(), GPIO_IS_OUTPUT(), ..
2. Lower level macros used within those functions translate port, pin to a register. E.g. GPIO_IN(), GPIO_SEL(), ..
The end result is code like you would write when directly working with the GPIO registers. E.g. P2OUT &= ~BIT0; Note that this translation is done by the C pre-processor before the code is compiled.
This all works fine and dandy, with the exception of port J. Port J doesn't have a SEL register, which breaks the 1st half of the GPIO_IS_OUTPUT and GPIO_IS_INPUT macros. I currently work around this by adding special GPIO_IS_OUTPUT/INPUT_J macros, but then the main code needs to include some logic to invoke the proper macro.
#if (LED2_PORT == J) GPIO_IS_OUTPUT_J(LED2_PORT, LED2_PIN); #else GPIO_IS_OUTPUT(LED2_PORT, LED2_PIN); #endif Any ideas, how I could include a condition inside macros, that checks whether the port is J, and if so excludes the GPIO_SEL command?
And yes, I could probably use C++ templates with identical results and an easy workaround for port J, but I'd like to avoid migrating my plain old C project.
Edit: Added a few missing parentheses, thanks to Rickta59 for spotting that
-
chicken got a reaction from will in Temperature & Humidity sensor -with LCD & RF
Re BSL: I plan to use the Python libraries myself to let users upgrade the firmware on my AIS Receiver HAT for the Raspberry Pi.
At least when trying to combine it with UART BSL compiled from source code (I can't use the built in BSL due to retarded pin assignment) the Python library turned out to be very buggy, to a level where I wonder if it was ever working for UART.
If I remember correctly, the bug with the CRC calculation was that it included the BSL header instead of just the payload. Attached the fixed libraries that work for me.
My code does not cover getting the device into bootloader mode, i.e. it assumes a separate procedure to get there (in my case selecting a menu option in a serial terminal). From there working with the BSL from Python works like this:
bsl_target = bsluart.SerialBSL5Target() bsl_target.logger.setLevel(logging.DEBUG) ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s') ch.setFormatter(formatter) bsl_target.logger.addHandler(ch) print "Connecting to BSL" bsl_target.open(args.port) print "BSL version:", bsl_target.version() bsl_target.detect_buffer_size() print "BSL buffer size:", bsl_target.buffer_size print "Writing into MCU memory" # bsl_target.memory_write(0x2866, "hello world") # bsl_target.execute(0x2866) bsl_target.close() As you can tell, it's still work in progress. But at least the communication with the bootloader on the MCU is now working.
bsluart.zip
-
chicken got a reaction from tripwire in How to prevent and detect stack overflow
Here's a great webinar on the topic of stack overflow from basics like stack sizing all the way to stack usage estimation and analysis, stack monitoring and stack overflow handling.
Recording:
Transcript: http://barrgroup.com/Embedded-Systems/How-To/Prevent-Detect-Stack-Overflow
Found via the Embedded Muse newsletter.
-
chicken reacted to will in Temperature & Humidity sensor -with LCD & RF
After quite a while, here is the voltage curve during ~92days
And still keep going, I guess it still cannot get to 180 days because the minimum supply voltage of HDC1080 is 2.7.
but the my other card is using HTU21D, which can operate until 2v.
While still testing the battery life, I'm designing the second version, and encounter some problem with BSL.
After seen the GoodFET42 design, I also want to put a USB to UART, so I can upload the firmware with USB.
I tried using python-msp430-tools (bsl5), and connect DTR to RST, RTS to TEST, and checked the BSL sequence and the response using Logic analyzer.
but it seems sending the wrong CRC (I seen the response as CRC error), not sure why python package sends the wrong CRC.
has anyone tried uploading to MSP430FR4133 using BSL?
Also, I seen 8pino is using PCB as micro USB socket, so I'll also try that
also looking for some new sensor, BME280 looks pretty good.
-
chicken got a reaction from bluehash in How to prevent and detect stack overflow
Here's a great webinar on the topic of stack overflow from basics like stack sizing all the way to stack usage estimation and analysis, stack monitoring and stack overflow handling.
Recording:
Transcript: http://barrgroup.com/Embedded-Systems/How-To/Prevent-Detect-Stack-Overflow
Found via the Embedded Muse newsletter.
-
chicken got a reaction from Fmilburn in How to prevent and detect stack overflow
Here's a great webinar on the topic of stack overflow from basics like stack sizing all the way to stack usage estimation and analysis, stack monitoring and stack overflow handling.
Recording:
Transcript: http://barrgroup.com/Embedded-Systems/How-To/Prevent-Detect-Stack-Overflow
Found via the Embedded Muse newsletter.
-
chicken got a reaction from yyrkoon in How to prevent and detect stack overflow
Here's a great webinar on the topic of stack overflow from basics like stack sizing all the way to stack usage estimation and analysis, stack monitoring and stack overflow handling.
Recording:
Transcript: http://barrgroup.com/Embedded-Systems/How-To/Prevent-Detect-Stack-Overflow
Found via the Embedded Muse newsletter.
-
chicken got a reaction from zeke in Basic MSP430 GPIO Macros
In my project, I use a few basic macros for GPIO. The goal is, that I can easily redefine pin assignment in a central location without compromising performance or code size.
The macros (gpiomacros.h):
// MSP430 gpio macros #define GPIO_SEL(port) P ## port ## SEL #define GPIO_DIR(port) P ## port ## DIR #define GPIO_OUT(port) P ## port ## OUT #define GPIO_IN(port) P ## port ## IN #define GPIO_IS_INPUT(port,pin) { GPIO_SEL(port) &= ~(pin); GPIO_DIR(port) &= ~(pin); } #define GPIO_IS_OUTPUT(port,pin) { GPIO_SEL(port) &= ~(pin); GPIO_DIR(port) |= (pin); } #define GPIO_IS_PERIPHERAL_IN(port,pin) { GPIO_SEL(port) |= (pin); GPIO_DIR(port) &= ~(pin); } #define GPIO_IS_PERIPHERAL_OUT(port,pin) { GPIO_SEL(port) |= (pin); GPIO_DIR(port) |= (pin); } #define GPIO_SET(port,pin) { GPIO_OUT(port) |= (pin); } #define GPIO_CLEAR(port,pin) { GPIO_OUT(port) &= ~(pin); } #define GPIO_READ(port,pin) ( GPIO_IN(port) & (pin) ) In a central configuration file (e.g. hardware.h) I assign pins like this:
// Pin assignment #define LED1_PIN BIT1 #define LED1_PORT 6 #define LED2_PIN BIT0 #define LED2_PORT 1 And then in the code I interact with GPIO like this:
// Setup LEDs GPIO_IS_OUTPUT(LED1_PORT, LED1_PIN); GPIO_IS_OUTPUT(LED2_PORT, LED2_PIN); // Turn off LEDs GPIO_CLEAR(LED1_PORT, LED1_PIN); GPIO_CLEAR(LED2_PORT, LED2_PIN); The macros are resolved in two steps:
1. Higher level "functions" define the commands. E.g. GPIO_SET(), GPIO_IS_OUTPUT(), ..
2. Lower level macros used within those functions translate port, pin to a register. E.g. GPIO_IN(), GPIO_SEL(), ..
The end result is code like you would write when directly working with the GPIO registers. E.g. P2OUT &= ~BIT0; Note that this translation is done by the C pre-processor before the code is compiled.
This all works fine and dandy, with the exception of port J. Port J doesn't have a SEL register, which breaks the 1st half of the GPIO_IS_OUTPUT and GPIO_IS_INPUT macros. I currently work around this by adding special GPIO_IS_OUTPUT/INPUT_J macros, but then the main code needs to include some logic to invoke the proper macro.
#if (LED2_PORT == J) GPIO_IS_OUTPUT_J(LED2_PORT, LED2_PIN); #else GPIO_IS_OUTPUT(LED2_PORT, LED2_PIN); #endif Any ideas, how I could include a condition inside macros, that checks whether the port is J, and if so excludes the GPIO_SEL command?
And yes, I could probably use C++ templates with identical results and an easy workaround for port J, but I'd like to avoid migrating my plain old C project.
Edit: Added a few missing parentheses, thanks to Rickta59 for spotting that
-
chicken reacted to Fmilburn in DriverLib Examples for the MSP430F5529
Energia and Arduino users eventually get to the point where they need more direct access to the hardware if they take on more complicated projects. In addition to the direct access of registers using the provided header files, TI offers DriverLib which contains abstractions for accessing the peripherals.
To better understand the peripherals, and to check out DriverLib, I recently created 20+ short examples for my own edification. All of them were written for the MSP430F5529 LaunchPad and most of the peripherals are covered. In some cases pushbuttons, LEDs, resistors, potentiometer, etc. are required that you probably have on hand. A multimeter is required, and in some cases an oscilloscope and logic analyzer are instructive but not necessary.
DriverLib SPI Example 13A_USCI_B_SPI_MCP41010_digiPot
All of the examples are located here: https://github.com/fmilburn3/MSP430F5529_driverlib_examples
It is necessary to have some understanding of the registers before using DriverLib because the DriverLib documentation doesn't describe how the peripherals and their registers work. The documentation for registers is located in the User
-
chicken reacted to Rickta59 in Basic MSP430 GPIO Macros
BTW: that macro is missing parens around the ~pin ... should be ~(pin)
-
chicken reacted to Rickta59 in Basic MSP430 GPIO Macros
These all seem to generate the same sized code ...
#include <msp430.h> #include <stdint.h> // MSP430 gpio macros #define GPIO_SEL(port) P ## port ## SEL #define GPIO_DIR(port) P ## port ## DIR #define GPIO_OUT(port) P ## port ## OUT #define GPIO_IN(port) P ## port ## IN #define GPIO_IS_INPUT(port,pin) { GPIO_SEL(port) &= ~(pin); GPIO_DIR(port) &= ~(pin); } #define GPIO_IS_OUTPUT(port,pin) { GPIO_SEL(port) &= ~(pin); GPIO_DIR(port) |= (pin); } #define GPIO_IS_PERIPHERAL_IN(port,pin) { GPIO_SEL(port) |= (pin); GPIO_DIR(port) &= ~(pin); } #define GPIO_IS_PERIPHERAL_OUT(port,pin) { GPIO_SEL(port) |= pin; GPIO_DIR(port) |= (pin); } #define GPIO_SET(port,pin) { GPIO_OUT(port) |= (pin); } #define GPIO_CLEAR(port,pin) { GPIO_OUT(port) &= ~(pin); } #define GPIO_READ(port,pin) ( GPIO_IN(port) & (pin) ) #define GPIO_PIN(pin) (1 << (pin)) __attribute__((always_inline)) static inline gpio_is_output(const unsigned port, const unsigned pinno) { switch(port) { case 1: P1SEL &= ~(1 << pinno); P1DIR |= 1 << pinno; break; case 2: P1SEL &= ~(1 << pinno); P1DIR |= 1 << pinno; break; } } //#define USE_MACRO void main(void) { WDTCTL = WDTPW|WDTHOLD; //DCOCTL -= 28; #if defined(USE_MACRO) GPIO_IS_OUTPUT(1,4); GPIO_IS_OUTPUT(1,6); GPIO_IS_OUTPUT(1,0); #elif defined(USE_INLINE_FUNC) gpio_is_output(1,4); gpio_is_output(1,6); gpio_is_output(1,0); #else P1SEL &= ~(BIT4); P1DIR |= BIT4; P1SEL &= ~(BIT6); P1DIR |= BIT6; P1SEL &= ~(BIT0); P1DIR |= BIT0; P1OUT &= ~BIT0; P1OUT |= BIT6; P1SEL |= BIT4; #endif #if defined(USE_MACRO) || defined(USE_INLINE_FUNC) GPIO_CLEAR(1,0); GPIO_SET(1,6); GPIO_SEL(1) |= GPIO_PIN(4); #endif for(;{ P1OUT ^= (BIT0|BIT6); __delay_cycles(1000000>>3); // delay } } At least with msp430-gcc. I didn't try with msp430-elf-gcc
$ msp430-gcc -Os -g gpio_test.c -mmcu=msp430g2553 -DUSE_INLINE_FUNC; msp430-size a.out; msp430-objdump -CS a.out >/tmp/inline.txt text data bss dec hex filename 180 0 2 182 b6 a.out $ msp430-gcc -Os -g gpio_test.c -mmcu=msp430g2553 -DUSE_MACRO; msp430-size a.out; msp430-objdump -CS a.out >/tmp/macro.txt text data bss dec hex filenameD 180 0 2 182 b6 a.out $ msp430-gcc -Os -g gpio_test.c -mmcu=msp430g2553 ; msp430-size a.out; msp430-objdump -CS a.out >/tmp/reg.txt text data bss dec hex filename 180 0 2 182 b6 a.out -
chicken reacted to yyrkoon in Basic MSP430 GPIO Macros
Hi Chicken,
So I thanked you for the first post. Because it think it's awesome when people share their code with others while offering up an explanation.
However, personally, I would not do this. Do keep in mind when I say this, that it's purely a personal preference, based on my coding beliefs. But basically, I would not do this because it "obfuscates" how things are done. It adds more code than is necessary, and it makes the code less readable at a glance.
Readability, one cold really argue both ways. But when I say it makes it harder to see what's happening at a glance. I mean literally. Like, if we create a macro to clear a bit on a port, interrupt, whatever. How do we know that macro is correct, or what it actually does without going through an implementation file or two ? Additionally, sometimes it may not be clear where the actual macro is. When working with larger projects, and the source is not yours.
Passed all that I do have a strong dislike for #define directives, as well as macros in general. For numerical values, I prefer to use const.
Then somewhere in my past, I've read that creating function like macro's is not really a good thing. Whether I still believe that is true or not is mostly irrelevant. But I still prefer to use standard C functions.
So, when I need to set, or clear, or whatever a pin, interrupt, port, or whatever. I prefer to do it right where it needs to be done, and in plain C. This also keeps me from becoming lazy, and forgetting "things" which I already have a hard time with. Since I jump around between several languages a lot . . .
I have to say though, if this works for you. Then keep it up
-
chicken reacted to roadrunner84 in Basic MSP430 GPIO Macros
You could consider using C++ template programming instead of C style defines.
I haven't tested this, but it would go something like this:
template <int port> void GPIO_IS_INPUT(int pin) { GPIO_SEL(port) &= ~(pin); GPIO_DIR(port) &= ~(pin); } template <> void GPIO_IS_INPUT<J>(int pin) { GPIO_DIR(J) &= ~(pin); } Now instead of passing port as a macro like function parameter, pass it as a template parameter
GPIO_IS_INPUT<LED1_PORT>(LED1_PIN); I'm not entirely sure this will work though; the double-hash preprocessor operator is very tricky.
You could go all the way with these templates and get gone with the macros entirely.
If you really want no function call overhead, just make them inline.
-
chicken reacted to enl in Basic MSP430 GPIO Macros
I tend to use this style for many things, in particular single thread embedded applications like one tends to have on the smaller MSP430's, but it isn't always my preference.
The code tends to be more readable if done reasonably well, with full optimization available since it is expanded by the preprocessor, but inline functions can be just as efficient and are often less likely to lead to debugging issues, making them generally preferable when available, but with the drawback that expansion is not mandatory, so timing is not guaranteed. If forced, you lose some space optimization features.
-
chicken got a reaction from agaelema in Basic MSP430 GPIO Macros
In my project, I use a few basic macros for GPIO. The goal is, that I can easily redefine pin assignment in a central location without compromising performance or code size.
The macros (gpiomacros.h):
// MSP430 gpio macros #define GPIO_SEL(port) P ## port ## SEL #define GPIO_DIR(port) P ## port ## DIR #define GPIO_OUT(port) P ## port ## OUT #define GPIO_IN(port) P ## port ## IN #define GPIO_IS_INPUT(port,pin) { GPIO_SEL(port) &= ~(pin); GPIO_DIR(port) &= ~(pin); } #define GPIO_IS_OUTPUT(port,pin) { GPIO_SEL(port) &= ~(pin); GPIO_DIR(port) |= (pin); } #define GPIO_IS_PERIPHERAL_IN(port,pin) { GPIO_SEL(port) |= (pin); GPIO_DIR(port) &= ~(pin); } #define GPIO_IS_PERIPHERAL_OUT(port,pin) { GPIO_SEL(port) |= (pin); GPIO_DIR(port) |= (pin); } #define GPIO_SET(port,pin) { GPIO_OUT(port) |= (pin); } #define GPIO_CLEAR(port,pin) { GPIO_OUT(port) &= ~(pin); } #define GPIO_READ(port,pin) ( GPIO_IN(port) & (pin) ) In a central configuration file (e.g. hardware.h) I assign pins like this:
// Pin assignment #define LED1_PIN BIT1 #define LED1_PORT 6 #define LED2_PIN BIT0 #define LED2_PORT 1 And then in the code I interact with GPIO like this:
// Setup LEDs GPIO_IS_OUTPUT(LED1_PORT, LED1_PIN); GPIO_IS_OUTPUT(LED2_PORT, LED2_PIN); // Turn off LEDs GPIO_CLEAR(LED1_PORT, LED1_PIN); GPIO_CLEAR(LED2_PORT, LED2_PIN); The macros are resolved in two steps:
1. Higher level "functions" define the commands. E.g. GPIO_SET(), GPIO_IS_OUTPUT(), ..
2. Lower level macros used within those functions translate port, pin to a register. E.g. GPIO_IN(), GPIO_SEL(), ..
The end result is code like you would write when directly working with the GPIO registers. E.g. P2OUT &= ~BIT0; Note that this translation is done by the C pre-processor before the code is compiled.
This all works fine and dandy, with the exception of port J. Port J doesn't have a SEL register, which breaks the 1st half of the GPIO_IS_OUTPUT and GPIO_IS_INPUT macros. I currently work around this by adding special GPIO_IS_OUTPUT/INPUT_J macros, but then the main code needs to include some logic to invoke the proper macro.
#if (LED2_PORT == J) GPIO_IS_OUTPUT_J(LED2_PORT, LED2_PIN); #else GPIO_IS_OUTPUT(LED2_PORT, LED2_PIN); #endif Any ideas, how I could include a condition inside macros, that checks whether the port is J, and if so excludes the GPIO_SEL command?
And yes, I could probably use C++ templates with identical results and an easy workaround for port J, but I'd like to avoid migrating my plain old C project.
Edit: Added a few missing parentheses, thanks to Rickta59 for spotting that
-
chicken got a reaction from enl in Basic MSP430 GPIO Macros
In my project, I use a few basic macros for GPIO. The goal is, that I can easily redefine pin assignment in a central location without compromising performance or code size.
The macros (gpiomacros.h):
// MSP430 gpio macros #define GPIO_SEL(port) P ## port ## SEL #define GPIO_DIR(port) P ## port ## DIR #define GPIO_OUT(port) P ## port ## OUT #define GPIO_IN(port) P ## port ## IN #define GPIO_IS_INPUT(port,pin) { GPIO_SEL(port) &= ~(pin); GPIO_DIR(port) &= ~(pin); } #define GPIO_IS_OUTPUT(port,pin) { GPIO_SEL(port) &= ~(pin); GPIO_DIR(port) |= (pin); } #define GPIO_IS_PERIPHERAL_IN(port,pin) { GPIO_SEL(port) |= (pin); GPIO_DIR(port) &= ~(pin); } #define GPIO_IS_PERIPHERAL_OUT(port,pin) { GPIO_SEL(port) |= (pin); GPIO_DIR(port) |= (pin); } #define GPIO_SET(port,pin) { GPIO_OUT(port) |= (pin); } #define GPIO_CLEAR(port,pin) { GPIO_OUT(port) &= ~(pin); } #define GPIO_READ(port,pin) ( GPIO_IN(port) & (pin) ) In a central configuration file (e.g. hardware.h) I assign pins like this:
// Pin assignment #define LED1_PIN BIT1 #define LED1_PORT 6 #define LED2_PIN BIT0 #define LED2_PORT 1 And then in the code I interact with GPIO like this:
// Setup LEDs GPIO_IS_OUTPUT(LED1_PORT, LED1_PIN); GPIO_IS_OUTPUT(LED2_PORT, LED2_PIN); // Turn off LEDs GPIO_CLEAR(LED1_PORT, LED1_PIN); GPIO_CLEAR(LED2_PORT, LED2_PIN); The macros are resolved in two steps:
1. Higher level "functions" define the commands. E.g. GPIO_SET(), GPIO_IS_OUTPUT(), ..
2. Lower level macros used within those functions translate port, pin to a register. E.g. GPIO_IN(), GPIO_SEL(), ..
The end result is code like you would write when directly working with the GPIO registers. E.g. P2OUT &= ~BIT0; Note that this translation is done by the C pre-processor before the code is compiled.
This all works fine and dandy, with the exception of port J. Port J doesn't have a SEL register, which breaks the 1st half of the GPIO_IS_OUTPUT and GPIO_IS_INPUT macros. I currently work around this by adding special GPIO_IS_OUTPUT/INPUT_J macros, but then the main code needs to include some logic to invoke the proper macro.
#if (LED2_PORT == J) GPIO_IS_OUTPUT_J(LED2_PORT, LED2_PIN); #else GPIO_IS_OUTPUT(LED2_PORT, LED2_PIN); #endif Any ideas, how I could include a condition inside macros, that checks whether the port is J, and if so excludes the GPIO_SEL command?
And yes, I could probably use C++ templates with identical results and an easy workaround for port J, but I'd like to avoid migrating my plain old C project.
Edit: Added a few missing parentheses, thanks to Rickta59 for spotting that
-
chicken got a reaction from LiviuM in Basic MSP430 GPIO Macros
In my project, I use a few basic macros for GPIO. The goal is, that I can easily redefine pin assignment in a central location without compromising performance or code size.
The macros (gpiomacros.h):
// MSP430 gpio macros #define GPIO_SEL(port) P ## port ## SEL #define GPIO_DIR(port) P ## port ## DIR #define GPIO_OUT(port) P ## port ## OUT #define GPIO_IN(port) P ## port ## IN #define GPIO_IS_INPUT(port,pin) { GPIO_SEL(port) &= ~(pin); GPIO_DIR(port) &= ~(pin); } #define GPIO_IS_OUTPUT(port,pin) { GPIO_SEL(port) &= ~(pin); GPIO_DIR(port) |= (pin); } #define GPIO_IS_PERIPHERAL_IN(port,pin) { GPIO_SEL(port) |= (pin); GPIO_DIR(port) &= ~(pin); } #define GPIO_IS_PERIPHERAL_OUT(port,pin) { GPIO_SEL(port) |= (pin); GPIO_DIR(port) |= (pin); } #define GPIO_SET(port,pin) { GPIO_OUT(port) |= (pin); } #define GPIO_CLEAR(port,pin) { GPIO_OUT(port) &= ~(pin); } #define GPIO_READ(port,pin) ( GPIO_IN(port) & (pin) ) In a central configuration file (e.g. hardware.h) I assign pins like this:
// Pin assignment #define LED1_PIN BIT1 #define LED1_PORT 6 #define LED2_PIN BIT0 #define LED2_PORT 1 And then in the code I interact with GPIO like this:
// Setup LEDs GPIO_IS_OUTPUT(LED1_PORT, LED1_PIN); GPIO_IS_OUTPUT(LED2_PORT, LED2_PIN); // Turn off LEDs GPIO_CLEAR(LED1_PORT, LED1_PIN); GPIO_CLEAR(LED2_PORT, LED2_PIN); The macros are resolved in two steps:
1. Higher level "functions" define the commands. E.g. GPIO_SET(), GPIO_IS_OUTPUT(), ..
2. Lower level macros used within those functions translate port, pin to a register. E.g. GPIO_IN(), GPIO_SEL(), ..
The end result is code like you would write when directly working with the GPIO registers. E.g. P2OUT &= ~BIT0; Note that this translation is done by the C pre-processor before the code is compiled.
This all works fine and dandy, with the exception of port J. Port J doesn't have a SEL register, which breaks the 1st half of the GPIO_IS_OUTPUT and GPIO_IS_INPUT macros. I currently work around this by adding special GPIO_IS_OUTPUT/INPUT_J macros, but then the main code needs to include some logic to invoke the proper macro.
#if (LED2_PORT == J) GPIO_IS_OUTPUT_J(LED2_PORT, LED2_PIN); #else GPIO_IS_OUTPUT(LED2_PORT, LED2_PIN); #endif Any ideas, how I could include a condition inside macros, that checks whether the port is J, and if so excludes the GPIO_SEL command?
And yes, I could probably use C++ templates with identical results and an easy workaround for port J, but I'd like to avoid migrating my plain old C project.
Edit: Added a few missing parentheses, thanks to Rickta59 for spotting that