Jump to content

chicken

Members
  • Content Count

    907
  • Joined

  • Last visited

  • Days Won

    85

Reputation Activity

  1. Like
    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
  2. Like
    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.
  3. Like
    chicken reacted to LiviuM in SPI between MSP430/432 and MCP3911   
    GND?
  4. Like
    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.
  5. Like
    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
  6. Like
    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
  7. Like
    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
  8. Like
    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
  9. Like
    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.
     
     
     
     
  10. Like
    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.
  11. Like
    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.
     
     
     
     
  12. Like
    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.
     
     
     
     
  13. Like
    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.
     
     
     
     
  14. Like
    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
  15. Like
    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
  16. Like
    chicken reacted to Rickta59 in Basic MSP430 GPIO Macros   
    BTW:  that macro is missing parens around the ~pin ... should be ~(pin)
  17. Like
    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
  18. Like
    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
  19. Like
    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.
  20. Like
    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.
  21. Like
    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
  22. Like
    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
  23. Like
    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
  24. Like
    chicken got a reaction from yyrkoon 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
  25. Like
    chicken reacted to Fmilburn in Using SPI and Energia with WS2812 LEDs   
    Nick Gammon published an interesting post on using SPI on 16 MHz Arduinos to run WS2812 LEDs (aka neopixels) at: http://gammon.com.au/forum/?id=13357. He also provides a link with a lot of information about the NRZ protocol used by the WS2812 and tolerances:  https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/.  The tolerances are actually quite a bit looser than what I previously believed.  So, I set out to do something similar with Energia and LaunchPads running at different speeds.  Spoiler alert:  It works.
     
    The previously linked articles provide all the background so minimal information is repeated here.  NRZ is a one wire protocol that transfers information to the LEDs by varying the length of the signal when high.  A longer pulse is used for a 1, and a shorter one for a 0.  The timing, with tolerances, is shown in the figure below.
     

    The length between pulses cannot exceed about 5 us and most everything else is pretty loose.
     
    The protocol is implemented using SPI which I find pretty clever.  A byte is sent out with the SPI module with the proper length to represent the desired bit for the protocol.  The following must be determined and set to do this:
    Set proper SPI clock speed using SPI.setClockDivider() in Energia Determine the proper byte to send by SPI.transfer() in Energia to represent a 0 or 1 bit For example, using the MSP430F5529:
    Clock speed is 25.6 MHz Setting the SPI clock divider to 4 gives a SPI clock of 6.4 MHz and since the SPI block executes in one cycle (Arduino executes in 2), each bit in the byte is equivalent to 156.25 ns. Therefore, to send a pulse indicating a "1", a byte equal to 0b1111000 could be used which gives 4x156.25 = 625 ns.  This is in the acceptable range of 550 to 850 ns. Similarly, for a 0 an acceptable byte would be 0b11000000 or 312.5 ns. A similar process can be used to determine acceptable values for the MSP430G2553.
     
    The sketch below is a simplification of the library presented by Nick which and includes the modifications described above to run on both the G2553 and F5529.  The preprocessor is used to set appropriate values for the clock divider and long and short bytes.   The functions are very nearly the same as posted by Nick.  Note that interrupts must be disabled before sending data and then reenabled manually after.
    /* * WS2812 display using SPI on various TI LaunchPads with Energia * * Connections: * LaunchPad LED Strip * --------- --------- * 3V3 5VDC * Pin 15 (MOSI) DIN * GND GND * * How to use: * ledsetup (); - Get ready to send. * Call once at the beginning of the program. * sendPixel (r, g, ; - Send a single pixel to the string. * Call this once for each pixel in a frame. * Each colour is in the range 0 to 255. Turn off * interrupts before use and turn on after all pixels * have been programmed. * show (); - Latch the recently sent pixels onto the LEDs . * Call once per frame. * showColor (count, r, g, ; - Set the entire string of count Neopixels * to this one colour. Turn off interrupts before use * and remember to turn on afterwards. * * Derived from NeoPixel display library by Nick Gammon * https://github.com/nickgammon/NeoPixels_SPI * With ideas from: * http://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/ * Released for public use under the Creative Commons Attribution 3.0 Australia License * http://creativecommons.org/licenses/by/3.0/au/ * * F Milburn November 2016 * Tested with Energia V17 and WS2812 8 pixel strip on launchpads shown below. */ #include <SPI.h> #if defined(__MSP430G2553) #define SPIDIV SPI_CLOCK_DIV2 // 16 MHz/2 gives 125 ns for each on bit in byte #define SPILONG 0b11111100 // 750 ns (acceptable "on" range 550 to 850 ns) #define SPISHORT 0b11100000 // 375 ns (acceptable "on" range 200 to 500 ns) #elif defined(__MSP430F5529) #define SPIDIV SPI_CLOCK_DIV4 // 25.6 MHz/4 gives 156.25 ns for each on bit in byte #define SPILONG 0b11110000 // 625 ns (acceptable "on" range 550 to 850 ns) #define SPISHORT 0b11000000 // 312.5 ns (acceptable "on" range 200 to 500 ns) #else #error This microcontroller is not supported #endif const unsigned int PIXELS = 8; // Pixels in the strip void setup (){ ledsetup(); } void loop (){ // Show a solid color across the strip noInterrupts(); // no interrupts while sending data showColor (PIXELS, 0xBB, 0x22, 0x22); // single color on entire strip interrupts(); // interrupts are OK now delay(1000); // hold it for a second // Show a different color on every pixel noInterrupts(); // no interrupts while sending data sendPixel(0xBB, 0x00, 0x00); // red sendPixel(0x00, 0xBB, 0x00); // green sendPixel(0x00, 0x00, 0xBB); // blue sendPixel(0xBB, 0xBB, 0xBB); // white sendPixel(0xBB, 0x22, 0x22); // pinkish sendPixel(0x22, 0xBB, 0x22); // light green sendPixel(0x22, 0x22, 0xBB); // purplish blue sendPixel(0x00, 0x00, 0x00); // pixel off interrupts(); // interrupts are OK now delay(1000); // hold it for a second } // Sends one byte to the LED strip by SPI. void sendByte (unsigned char { for (unsigned char bit = 0; bit < 8; bit++){ if (b & 0x80) // is high-order bit set? SPI.transfer (SPILONG); // long on bit (~700 ns) defined for each clock speed else SPI.transfer (SPISHORT); // short on bit (~350 ns) defined for each clock speed b <<= 1; // shift next bit into high-order position } // end of for each bit } // end of sendByte // Set up SPI void ledsetup(){ SPI.begin (); SPI.setClockDivider (SPIDIV); // defined for each clock speed SPI.setBitOrder (MSBFIRST); SPI.setDataMode (SPI_MODE1); // MOSI normally low. show (); // in case MOSI went high, latch in whatever-we-sent sendPixel (0, 0, 0); // now change back to black show (); // and latch that } // end of ledsetup // Send a single pixel worth of information. Turn interrupts off while using. void sendPixel (unsigned char r, unsigned char g, unsigned char { sendByte (g); // NeoPixel wants colors in green-then-red-then-blue order sendByte (r); sendByte (; } // end of sendPixel // Wait long enough without sending any bits to allow the pixels to latch and // display the last sent frame void show(){ delayMicroseconds (9); } // end of show // Display a single color on the whole string. Turn interrupts off while using. void showColor (unsigned int count, unsigned char r , unsigned char g , unsigned char { noInterrupts (); for (unsigned int pixel = 0; pixel < count; pixel++) sendPixel (r, g, ; interrupts (); show (); // latch the colours } // end of showColor The timing, when checked on a logic analyzer, checks out with the calculations above (hooray for math).  The "gaps" between pulses are within tolerance and largely set by code overhead as well as the byte being sent.
     


    And here it is showing the strip lit up in one color.
     

    I tried this on several other LaunchPads I had handy and here is a summary:
    FR6989 - I had never noticed, but Energia defaults to 8 MHz.  Doing the math, there isn't a good match to the WS2812 requirements without changing processor speed (which I did not try). MSP432 - there was behavior I couldn't explain, probably due to RTOS and I didn't pursue this for long. In summary, the method works although I did limited experimentation.  It would be even easier to implement outside of Energia with full access to clocks.  It was an interesting exercise but alternative methods have been posted here on 43oh with tuned assembler and having used those successfully in the past, I will probably continue to preferentially use them in the future.
×
×
  • Create New...