Jump to content
43oh

Automate

Members
  • Content Count

    253
  • Joined

  • Last visited

  • Days Won

    7

Reputation Activity

  1. Like
    Automate got a reaction from legailutin in TI Back to School Promotion   
    It's available now http://e2e.ti.com/blogs_/b/msp430blog/archive/2013/08/25/back-to-school-sale-part-2-sa430.aspx
     
    Coupon code SA_BTS
  2. Like
    Automate got a reaction from pine in TI Back to School Promotion   
    It's available now http://e2e.ti.com/blogs_/b/msp430blog/archive/2013/08/25/back-to-school-sale-part-2-sa430.aspx
     
    Coupon code SA_BTS
  3. Like
    Automate got a reaction from kodi in Grove Booster Pack Design   
    A Grove Booster Pack has been developed on Upverter.
     

     
    A few words about the design.
    Seeed Studio's Grove I/O Expansion BoosterPack is designed to enable interfacing between Texas Instruments (TI) LaunchPads and the Grove modular electronics ecosystem. To provide a straightforward means of evaluating single function modules, such as sensors, actuators, and displays, with the embedded intelligence of a microcontroller platform, the Grove BoosterPack will streamline the process for entry level users, students, and hobbyists. Though oriented towards TI's 40-pin LaunchPad series, the Grove BoosterPack will also perform on TI's 20-pin LaunchPad series with a limited number of connectors.
    The Grove BoosterPack's full listing of features includes:
    Selectable module supply voltage of 3.3V or 5V Approximately 100 Grove modules to select from Shrouded, 4-pin buckle connectors to lock-in modules 23 total connectors13 Digital connectors 7 Analog connectors 3 Specialized connectors (UART, SPI, and I2C) For more information on TI's LaunchPads, visit www.ti.com/launchpad 
    For more information on Seeed Studio's Grove, visithttp://www.seeedstudio.com/depot/grove-t-3.html?ref=top
    http://blog.upverter.com/design-of-the-week-by-a-whitehead
     
    https://upverter.com/a-whitehead/3cebfa8448f208b0/SIMPLE-LaunchPad-BoosterPack-for-Seeed-Studios-Grove/
  4. Like
    Automate reacted to tsupplis in AFE Launchpad Board   
    Below is a take at creating a small launchpad style board with the MSP430AFE, This board is my first ever design of a Circuit/PCB so it probably contains a lot of design mistakes. Any feedback/advices/criticism will be much appreciated. I can't wait to get a good bashing from the site members.
     
    I was able to pull that out despite my 'newby-ness' thank's in particular to the good learning environment that this site provides. Thank you so to all the people who have pushed their designs before with ample explanation and details.
     
    The board was design to leverage the AFE for an open source metering project.


    ts_afe.zip
  5. Like
    Automate reacted to energia in Energia - "Maintenance Release"?   
    It has indeed been a long time since we have done a release. Although not officially announced yet (shhhhhh..), there is a release planned for Sep 12. So please hang in there for a couple more weeks.
  6. Like
    Automate got a reaction from spirilis in Grove Booster Pack Design   
    A Grove Booster Pack has been developed on Upverter.
     

     
    A few words about the design.
    Seeed Studio's Grove I/O Expansion BoosterPack is designed to enable interfacing between Texas Instruments (TI) LaunchPads and the Grove modular electronics ecosystem. To provide a straightforward means of evaluating single function modules, such as sensors, actuators, and displays, with the embedded intelligence of a microcontroller platform, the Grove BoosterPack will streamline the process for entry level users, students, and hobbyists. Though oriented towards TI's 40-pin LaunchPad series, the Grove BoosterPack will also perform on TI's 20-pin LaunchPad series with a limited number of connectors.
    The Grove BoosterPack's full listing of features includes:
    Selectable module supply voltage of 3.3V or 5V Approximately 100 Grove modules to select from Shrouded, 4-pin buckle connectors to lock-in modules 23 total connectors13 Digital connectors 7 Analog connectors 3 Specialized connectors (UART, SPI, and I2C) For more information on TI's LaunchPads, visit www.ti.com/launchpad 
    For more information on Seeed Studio's Grove, visithttp://www.seeedstudio.com/depot/grove-t-3.html?ref=top
    http://blog.upverter.com/design-of-the-week-by-a-whitehead
     
    https://upverter.com/a-whitehead/3cebfa8448f208b0/SIMPLE-LaunchPad-BoosterPack-for-Seeed-Studios-Grove/
  7. Like
    Automate got a reaction from JWoodrell in Grove Booster Pack Design   
    A Grove Booster Pack has been developed on Upverter.
     

     
    A few words about the design.
    Seeed Studio's Grove I/O Expansion BoosterPack is designed to enable interfacing between Texas Instruments (TI) LaunchPads and the Grove modular electronics ecosystem. To provide a straightforward means of evaluating single function modules, such as sensors, actuators, and displays, with the embedded intelligence of a microcontroller platform, the Grove BoosterPack will streamline the process for entry level users, students, and hobbyists. Though oriented towards TI's 40-pin LaunchPad series, the Grove BoosterPack will also perform on TI's 20-pin LaunchPad series with a limited number of connectors.
    The Grove BoosterPack's full listing of features includes:
    Selectable module supply voltage of 3.3V or 5V Approximately 100 Grove modules to select from Shrouded, 4-pin buckle connectors to lock-in modules 23 total connectors13 Digital connectors 7 Analog connectors 3 Specialized connectors (UART, SPI, and I2C) For more information on TI's LaunchPads, visit www.ti.com/launchpad 
    For more information on Seeed Studio's Grove, visithttp://www.seeedstudio.com/depot/grove-t-3.html?ref=top
    http://blog.upverter.com/design-of-the-week-by-a-whitehead
     
    https://upverter.com/a-whitehead/3cebfa8448f208b0/SIMPLE-LaunchPad-BoosterPack-for-Seeed-Studios-Grove/
  8. Like
    Automate reacted to arre in Electric Scooter LCD on dashboard, powered by a TI Stellaris Launchpad   
    Hi all,
     
    Another project to the list: 
     
    I fitted my electric scooter with an LCD on my dashboard, to display power consumption and the voltages of the batteries, using the stellaris launchpad.
    The launchpad provided the digital out pins for the LCD (thanks to The_YonGrand for the lib), and the ADC measurements for the voltages & current of the battery.
     
    You can it out in detail on my blog: http://arre234.blogspot.be/ , or directly take a peak in the code on https://github.com/arre525/escooterlcd
     
    But here are already a few pictures to get you interested:)
     
     
     
     

     
     

     
     

     
    Arnout
  9. Like
    Automate got a reaction from bluehash in SXSW Interactive - Vote for our panel session.   
    Me too
  10. Like
    Automate reacted to Funklord in Moon Shoot game for the ez430 Chronos wristwatch   
    A shooter action game for the ez430 Chronos wristwatch.
    I made this game in one afternoon.
    The backlight effects can barely be seen on the video and the SFX are still very primitive.
    Hopefully it can be improved in a v2.
     


     
    Someone told me to share it here ;-)
  11. Like
    Automate reacted to nemetila in LAUNCHXL-F28027 - C2000 Piccolo LaunchPad Deal - $8.50   
    Happy 1st birthday, C2000 Piccolo LaunchPad:
    https://estore.ti.com/LAUNCHXL-F28027-C2000-Piccolo-LaunchPad-P3088.aspx
  12. Like
    Automate reacted to HanzZ in QSimKit - MSP430 simulator   
    Hi,
     
    as my diploma thesis I'm writting MSP430 simulator called QSimKit. It's not finished yet, but it's in state when it's starting to be useful and I would like to get more people to test it, share their opinions, find bugs and basically to create community of people interested in MSP430 simulation.
     
    Releases:
    Version 0.0.3 (2014-02-04), Changelog At first some facts about QSimKit:
    It's written under GPLv2+ in C++/Qt, has been tested on Linux or Windows together with msp430gcc. It supports peripherals (as plugins) written in C++ or Python. Currently there's LED, oscillator, button and HD44708 LCD (not fully implemented yet). MCUs are plugins too and theoretically it's possible to add support for more MCUs (not just MSP430). It can support all MSP430 variants, but only few are supported right now, because I haven't created package data for all MSP430 variants yet. In graphical user interface (Check screenshot), you can do following:
    Add peripherals, connect them to MCU. See the source code of program you are simulating together with Dwarf debugging data (you can see the value of local variables for example) and current instruction. Step the simulation, add breakpoints based on PC register or value of memory. Track pins in oscilloscope-like view. See the registers and other important values from MCU (frequency, BasicClock registers, ...) MSP430 MCU plugin can do following:
    Load ELF/A43 code. Supports all instructions. Supports BasicClock module (TImerA/TimerB). Support for USCI-SPI [NEW in 0.0.3] Support for USART-SPI [NEW in 0.0.3] Initial USI support (just SPI mode). Peripherals:
    Button LCD - HD44708 (only initial support) LED Crystal Oscillator SD Card (only initial support) [NEW in 0.0.2]  
    As I stated earlier, it's not finished yet, but some testers to help me testing are welcome. I can also help anyone who would like to help with development. There is no development documentation yet, but if you tell me what you would like to do, I can write relevant docs to help you.
     
    If you think you have found a bug or you have some feature request, please create ticket on GitHub, I don't want this forum thread to be an issue tracker. You can also find me on IRC in #qsimkit at freenode or as HanzZ in #43oh channel.
  13. Like
    Automate reacted to dubnet in Color LCD Booster Pack   
    @Kabron  First of all, welcome to the forum.,
     
    Based on your posts thus far, it appears that you may not fully understand what this board/community is all about. It is a forum for sharing experiences and experimetation around the TI MSP430 series MCUs. Although there is a store, the understanding is that it is there to facilitate that experimentation by providing "building blocks" which save others in the community time and effort.  In fact, the store also helps Bluehash to offset the costs associated with maintaining this board.  As @@RobG stated in his post, for most this is a hobby and not a full time commercial endevour so please do not expect commercial level support. However, most in the commmunity are happy to help with questions from other community members, regardless of their experience level. 
     
    RobG, despite his limited time, is a prolific contributor to this community and has helped many a member (including myself).  If you note the reputation rating under the member's name, it represents the number of times they have been thanked by other users of the community.
     
    Hopefully you are not offended in any way by my post.  My intent was to clarify the intent of the community and to facilitate realistic expectations.
     
    All the best and I sincerely hope that you can get as much enjoyment out of this community that I do.
  14. Like
    Automate reacted to spirilis in CAN BoosterPack   
    43oh Store: Buy the CAN BoosterPack for $14.99.
     
    This is a universal BoosterPack for enabling CAN I/O for all the LaunchPad-capable products.  It sports an NXP TJA1051T/3 CAN transceiver which includes a "V_IO" rail for doing native 3.3V CMOS I/O with the CAN controller.
     
    Included is the footprint for the Microchip MCP2515, SPI CAN Controller.  This is used to enable CAN connectivity for devices that do not have it natively supported.
    This is optional though.  If you do not need the MCP2515, the CAN_RX and CAN_TX pads can be soldered to breakout pads inside the boosterpack arrangement that correspond to the requisite pins on the LaunchPad which have CAN capability.  Stellaris/Tiva and Hercules LaunchPads should be able to take advantage of this.
    In that arrangement, the boosterpack simply supplies the CAN transceiver (physical-layer interface) as well as connectivity ports and the ability to supply or tap into a 5V rail going along the RJ45/CAT5 bus.
     
    I decided to choose RJ45 (non-magjack) for the physical connection, primarily due to its versatility as a way to chain multiple LaunchPads together into a long-distance CAN bus arrangement and due to its general-purpose nature.  Most people use CAN to connect to their automobile; for this I will be producing a daughterboard that converts DE9 (DB9) OBD-II standard pinout into the Industrial CAN RJ45 standard, including the adaption of 12V automotive power down to 5V for powering the LaunchPad.  An OBD-II to DE9 cable will need to be supplied separately to connect this arrangement but they are easy to come by; see here for an example: https://www.sparkfun.com/products/10087
     
    Support for terminating the CAN bus is included, and this board supports the Split-Bus configuration with two 60R resistors and a single 4.7nF capacitor to provide a noise sink.  This should be done at either end of the CAN bus, but nodes in the middle shouldn't need it.  If any nodes are connected to the bus with a stub (not in-line but branched off using some sort of 3-port concentrator), it is recommended they use termination with two 1.3K-ohm resistors.  This is not likely necessary thanks to the two RJ45 ports provided on the board which facilitate connecting nodes "in-line" to the bus.
     
    The 5V rail (CAN_V+) in the RJ45 connection can be attached directly to the LaunchPad's 5V rail in order to let the LaunchPad supply power to the whole bus, or it can be connected through a Current-Limiting IC to supply the LaunchPad's 5V rail along with bulk capacitance (SMD 1206 and/or PTH aluminum electrolytic capacitors; supply bulk capacitance to the board to survive long-distance cabling).
    To support using the 5V supply from the MSP430 LaunchPad, a "5VTAP" pad in the upper left is supplied which you can connect to TP1 (right behind the USB connector).  If you are powering the MSP430 LaunchPad from the CAN bus itself this is not needed (the MCP1725 voltage regulator will supply the 3.3V Vcc rail).
     
    OSHpark mockup pics:

     

     
     
    !!! NOTE : this design has major bugs, update forthcoming !!!
    Schematic (PDF): DipTrace Schematic - SPI_CAN_BPak_draft1.pdf
    OSHpark gerbers: OSH_SPICAN_v10.zip
    Elecrow/Seeed/ITead gerbers: Elecrow_SPICANv10_5x10.zip
    !!! NOTE : this design has major bugs, update forthcoming !!!
    This board is intended to use the 5x10cm PCB service from the Chinese fabs.
  15. Like
    Automate reacted to patolin_01 in Stellaris fast analog reads   
    Well, here is my 2 cents.
     
    Im working on a kind of DSO using the stellaris launchpad, and visual basic 2010.
     
    Right now, the stellaris can sample in 1 channel (pin PA7) at different speeds, selectable via serial port commands. Right now, it can sample at 1Msps (890Ksps real), 500Ksps, 250Ksps, 125Ksps using ADC interrupt, and 64ksps, 32ksps, 16ksps, 8ksps, and 2 ksps using timer interrupt.
     
    My code samples a 4096 samples buffer, and when receives the "c" command, it sends the values stored in the buffer in ASCII over the serial port, and the its plotted on the VB app. pretty simple, but for me resulted very useful.
     
    Here is my code
    // stelarisDSO v1.0 // 2013-07-20 // buffer de 4096 muestras // #include "Energia.h" #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "inc/hw_ints.h" #include "driverlib/debug.h" #include "driverlib/interrupt.h" #include "driverlib/sysctl.h" #include "driverlib/adc.h" #include "driverlib/timer.h" #define numDatos 4095 int i=0; int j=1; int adc[numDatos]; unsigned char dataReady=0; unsigned long ulADC0Value[1]; int datosListos=0; int datoActual=0; void setup() { int i; Serial.begin(115200); pinMode(RED_LED, OUTPUT); pinMode(BLUE_LED, OUTPUT); pinMode(GREEN_LED, OUTPUT); for (i=0;i<=4;i++) { digitalWrite(GREEN_LED,1); digitalWrite(RED_LED,1); digitalWrite(BLUE_LED,1); delay(100); digitalWrite(GREEN_LED,0); digitalWrite(RED_LED,0); digitalWrite(BLUE_LED,0); delay(100); } Serial.println("Stellaris DSO"); Serial.println("(c) 2013 www.patolin.com"); Serial.println("Inicio OK. "); Serial.print(SysCtlClockGet()); Serial.println(" hz"); initADC(0,0); ADCIntDisable(ADC0_BASE, 3); initTimer(500); } void loop() { int valor; unsigned timerADC=500; unsigned velADC=0; unsigned char serialIn; char tipoSampling=1; // 0=ADC int, 1=TIMER int // esperamos comando para la velocidad de muestreo while (1) { if (Serial.available()==1) { serialIn=Serial.read(); switch (serialIn) { case 's': // status Serial.println("Ok."); break; case 'c': // devuelve los datos del buffer // esperamos a los datos while (!datosListos) {} // paramos las interrupciones TimerIntDisable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); ADCIntDisable(ADC0_BASE, 3); datosListos=0; datoActual=0; //enviamos los datos por el puerto serie Serial.println(numDatos); for (i=0;i<=(numDatos-1);i++) { Serial.println(adc[i]); } // reiniciamos las interrupciones if (tipoSampling==1) { TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); } else { ADCIntEnable(ADC0_BASE, 3); } break; case '1': // 1ksps timerADC=500; tipoSampling=1; break; case '2': // 2ksps timerADC=1000; tipoSampling=1; break; case '3': // 4ksps timerADC=2000; tipoSampling=1; break; case '4': // 8ksps timerADC=4000; tipoSampling=1; break; case '5': // 16ksps timerADC=8000; tipoSampling=1; break; case '6': // 32ksps timerADC=16000; tipoSampling=1; break; case '7': // 64ksps timerADC=32000; tipoSampling=1; break; case '8': // 125ksps timerADC=0000; velADC=0; tipoSampling=0; break; case '9': // 250ksps timerADC=0000; velADC=1; tipoSampling=0; break; case 'A': // 500ksps timerADC=0000; velADC=2; tipoSampling=0; break; case 'B': // 1Msps timerADC=0000; velADC=3; tipoSampling=0; break; } // inicializamos el timer o el ADC segun el caso datosListos=0; datoActual=0; if (tipoSampling==0) { // ADC por interrupcion TimerIntDisable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); initADC(velADC,1); digitalWrite(RED_LED, 0x00); digitalWrite(BLUE_LED, 0x01); } else { ADCIntDisable(ADC0_BASE, 3); initTimer(timerADC); digitalWrite(RED_LED, 0x00); digitalWrite(BLUE_LED, 0x00); } } } } int capturaADC() { ADCIntClear(ADC0_BASE, 3); ADCProcessorTrigger(ADC0_BASE, 3); while(!ADCIntStatus(ADC0_BASE, 3, false)) { } ADCSequenceDataGet(ADC0_BASE, 3, ulADC0Value); return (int)ulADC0Value[0]; } void Timer0IntHandler() { TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT); digitalWrite(RED_LED, j&0x01); j++; adc[datoActual]=capturaADC(); datoActual++; if (datoActual>numDatos) { datosListos=1; datoActual=0; } } void ADC0IntHandler() { ADCIntClear(ADC0_BASE,3); ADCSequenceDataGet(ADC0_BASE, 3, ulADC0Value); adc[datoActual]=(int)ulADC0Value[0]; datoActual++; if (datoActual>numDatos) { datoActual=0; datosListos=1; ADCIntDisable(ADC0_BASE, 3);} } void initTimer(unsigned Hz) { SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC); unsigned long ulPeriod = (SysCtlClockGet() / Hz) / 2; TimerLoadSet(TIMER0_BASE, TIMER_A, ulPeriod -1); IntEnable(INT_TIMER0A); TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); TimerIntRegister(TIMER0_BASE, TIMER_A, Timer0IntHandler); TimerEnable(TIMER0_BASE, TIMER_A); } void initADC(int velocidad, int trigger) { /* Velocidad: 0=1msps,1=500ksps,2=250ksps,3=125ksps trigger: 0=processor, 1=always */ SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); switch(velocidad) { case 3: SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS); break; case 2: SysCtlADCSpeedSet(SYSCTL_ADCSPEED_500KSPS); break; case 1: SysCtlADCSpeedSet(SYSCTL_ADCSPEED_250KSPS); break; case 0: SysCtlADCSpeedSet(SYSCTL_ADCSPEED_125KSPS); break; default: SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS); break; } ADCSequenceDisable(ADC0_BASE, 3); if (trigger==0) { ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_PROCESSOR, 0); } else { ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_ALWAYS, 0); } ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END); //ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_TS | ADC_CTL_IE | ADC_CTL_END); //Secuencia de ejemplo para el medidor de temperatura interno ADCIntRegister(ADC0_BASE, 3, ADC0IntHandler); ADCIntEnable(ADC0_BASE, 3); ADCSequenceEnable(ADC0_BASE, 3); ADCProcessorTrigger(ADC0_BASE, 3); } Im writing a detailed post for my blog, so I hope it can be useful for you guys. You can check a preview (in spanish) in http://patolin.com/blog/2013/07/07/osciloscopio-con-stellaris-launchpad-actualizacion/
     
    Here is a capture image, of a RC transmitter PPM frame, at 125Ksps, 10 bits, using a 4096 sample buffer
     

  16. Like
    Automate reacted to chicken in Energia Library Devs - Thank you!   
    Thank you for asking.
     
    Personally, 43Oh store discounts won't make a difference to me. Compared to other hobbies, tinkering with LaunchPads is already pretty cheap
     
    How about convincing TI (and other vendors) to give evaluation boards for new ICs to proven library developers, with the explicit goal to publish an Energia library for it?
     
    I envision a program similar to the Dangerous Prototypes Free PCB drawer:
    1) Qualify for the program by publishing an Energia library
    2) Get a free chip/breakout/evaluation kit
    3) Publish Energia library for it
    4) Rinse and repeat
     
    A similar cycle could work for Booster Packs.
  17. Like
    Automate reacted to vinietje in [Energia Library] Ported RemoteSwitch to Energia   
    Hey All,
     
    I've ported the RemoteSwitch library to Energia, For now i've only teste the receiving part, which works.
     
    I've used the MSP430G2452 in accordens with the CZS-3 SAW receiver, all works on 432.93mzh Or 433.
     
    It it can be used to controll Action, Blokker and Klik-aan-Klik uit devices like power sockets, and receive the remote control presses.
     
    So far the sending part and the optional RemoteSensor I haven't touched (yet).
     
    the code is hosted on Github: https://github.com/vinietje/RemoteSwitchEnergiaPort
    Please note that i've written/run this code using a current git-checkout of Energia, rather than the energia-0101E0009-macosx.dmg build. (which appear to have a bug regarding external interrupts (which this port basically is all about).
     
    Have fun using it, and keep in mind: all credit to the original authors!
     
    Cheers
  18. Like
    Automate reacted to reaper7 in [Energia Library] StellarPad Mirf (nrf24l01+) library   
    Based on original Arduino Mirf library with some modifications on hardware spi.
    Works well with other devices on the same spi bus eg 5110 lcd
     
    New version 0.4 [28.04.2013]:
    1. For clarity *.ino files I decided to move SPI initialize to library.
    from now declaration of parameters should look like this: Nrf24l Mirf(CSN_PIN(def.PA_7), CE_PIN(def.PA_6), CHANNEL(def.1), PAYLOAD(def.16), SPI_MODULE(def.2));
    eg.:
    - Nrf24l Mirf(PA_7, PA_6, 1, 16); //DEFAULT SPI module 2
    - Nrf24l Mirf(PA_7, PA_6, 1, 16, 3); //SPI module 3
     
    SPI speed is defined in Mirf.cpp file (line 66), maybe more sense is move SPI speed to declaration too?
     
    Mirf_v0.4.zip
    Mirf_v0.3.zip
  19. Like
    Automate got a reaction from dubnet in MikroElektronika Click Boards   
    MikroElektronika has a large selection of over 60 Click Boards that connect to a Tiva / Stellaris Launchpad through a Booster adapter board.
     

     
    Worth a look if you don't want to design/build your own board.
    http://www.mikroe.com/click/
     
    RFid click Fiber Opt click 3.3V Fiber Opt click 5V ccRF click click USB adapter Adapter click FM click EVE Click BarGraph click Light click Pressure click FTDI click Current click 8x8 B click Bluetooth2 click 4-20 mA R click Compass click GYRO click IR click GSM2 click GPS2 click RELAY click OSD click DALI Click click BOOSTER PACK IrThermo click 3.3V IrThermo click 5V 8x8 G click nRF T click nRF C click GSM Click 8x8 Y click 8x8 R click 4-20 mA T click USB SPI click USB UART click 7seg click EEPROM Click Flash Click THERMO click OPTO click IrDA2 click Accel click WiFi Plus Click GPS Click - L10 CAN SPI click 5V CAN SPI click 3.3V LightHz click RS485 click 3.3V BEE click ETH Click Bluetooth Click GPS Click EXPAND click SHT11 click DAC Click RTC2 click RTC Click Buzz Click MP3 Click RS485 click 5V DIGI POT click ADC click microSD click
  20. Like
    Automate reacted to nimblemotors in Tractor Engine Control   
    The code I posted was just the fuel injection control.  The ignition control is an independant msp430 board.
    Here is the code for the ignition.  Was looking at it today, as I've got a new project to control a 12A rotary engine
    that is going into a jet boat I'm building, so thought I'd post it while I have it up. This code is much cleaner as it was all finished, unlike the EFI which was still a work in progress.
     
    Hope it helps someone.
     
    Cheers,
    Jack
    #include <signal.h> #include <io.h> #include <msp430/usart.h> #include <msp430/common.h> #include <msp430/basic_clock.h> // Ignition Controller for 4-cyl coil-on-plug tractor, written by Jack Murray 2011 // We have a hall-effect crank sensor with 8 magnets, 1 missing, 45-degree before TDC // We have two outputs to fire the two coils, one for cyl 1-4, and second for cyl 2-3 // // We have the magnets spaced evenly 45-degree apart. // The missing magnet is 135 degrees before #1 TDC, // We must have at least 3 triggers to get the timing between triggers // and then recognize the missing magnet as double the previous two triggers // then we know the next trigger is TDC and can calculate the delay needed // for the timing advance. // // The engine cranking rpm is quite low, about 200 RPM, revolutions per minute. // 200 RPM = 3.33 Revolutions per Second * 8 triggers = 26.64 triggers/sec // 26.64 triggers/sec = 1/26.64 = .0375 sec/trigger or 37.5 ms // The tractor motor 4-cyl has a governer that limits it to 2200 rpm // 2200 rpm = 36.666 RpS * 8 = 293 triggers/sec = .003409 sec/trigger or 3.40 ms // 2000 rpm = 33.333 RpS * 8 = 266 triggers/sec = .00375 sec/trigger or 3.75 ms // // determine rpm from tigger ms: ms per trigger 1/x = rev per sec / 8 * 60 = rpm // // we use a 32Khz clock signal, so we have 32 clock ticks per millisecond. // 200rpm, 37.5ms * 32 = 1200 clock ticks // 2000rpm, 3.4ms * 32 = 108 clock ticks // F1122 board #define ledOn() P2OUT &= ~0x08; // Led ON p2.3 #define ledOff() P2OUT |= 0x08; // Led Off p2.3 #define tachHigh() P1OUT |= 0x04; // 3v tach output == coil1 #define tachLow() P1OUT &= ~0x04; #define coil1High() P1OUT |= 0x01; // coil1 is trigger by p1.0 #define coil1Low() P1OUT &= ~0x01; #define coil2High() P1OUT |= 0x02; // coil2 is trigger using p1.1 #define coil2Low() P1OUT &= ~0x02; unsigned int lastCount = 0; unsigned int currentTime = 0; unsigned int thisTime = 0; unsigned int doubleTime = 0; unsigned int lastTime0 = 0; unsigned int lastTime1 = 0; unsigned int lastTime2 = 0; //for debugging unsigned short di = 0; unsigned short dbgsize = 48; unsigned short dbg[49]; unsigned short tachIsLow = 0; unsigned int timeadv = 0; unsigned short tar = 0; unsigned short xtar = 0; unsigned short ztar = 0; // // Watchdog Timer interrupt service routine // we don't use it interrupt (WDT_VECTOR) wdt() { } // // P1 Interrupt not used // interrupt (PORT1_VECTOR) p1int(void) { P1IFG = 0; // clear handled interrupt } void restartTimer() { // 32khz clock, restart at zero, interrupt enable, divide clock by 1, run to 0-0xffff TACTL = TASSEL_ACLK + TACLR + TAIE + ID_DIV1 + MC_CONT; } // // if we get a fatal error, blink the led slowly until we power cycle to reset // void crankError() { while(1) { TACTL = TASSEL_ACLK + TACLR + MC_CONT; ledOn(); // Led ON tar = TAR; // wait half second while (tar < 0xF000) { tar = TAR; } TACTL = TASSEL_ACLK + TACLR + MC_CONT; ledOff(); // Led ON tar = TAR; while (tar < 0xF000) { tar = TAR; } } } // // To fire the coil using the BIP373 darlington, we pull it low to break the connection to ground // and force the secondary to high voltage ground through the spark plug. // We must keep it off and then turn it back on about 2-4ms before the next firing to give // the coil(s) time to charge up before the next firing. // void firecoil(int which) { if (which == 1) { ledOn(); // turn on LED only for cylinder 1-4 coil1Low(); tachLow(); } else if (which == 2) { coil2Low(); tachLow(); } } // setup the timing advance for the coil // for the current rpm // determine rpm from tigger ms: ms per trigger 1/x = rev per sec / 8 * 60 = rpm // (1 / ((RPM / 60) * 8)) * 1000 * 32 = clock ticks // we use a 32Khz clock signal, so we have 32 clock ticks per millisecond. // doing advance computation takes too long with our little 4mhz processor, // so we reduce it to just use a table lookup. // here is the table calculations for 0-2500 rpm // advance ticks // RPM tickper45 /32 /16 /8 /45.0 30 20 16 12 8 6 4 // ------- --------- --- --- --- ----- -------------------------------------- // 2500 : 97 : 3 : 6 : 12 : 2.17 32 : 54 : 62 : 71 : 75 : 80 : 84 36 = 19 // 2450 : 100 : 3 : 6 : 12 : 2.22 33 : 55 : 64 : 73 : 77 : 82 : 86 35 = 22 // 2400 : 100 : 3 : 6 : 12 : 2.22 33 : 55 : 64 : 73 : 77 : 82 : 86 34 = 24 // 2350 : 102 : 3 : 6 : 12 : 2.28 34 : 56 : 66 : 75 : 79 : 84 : 88 33 = 27 // 2300 : 105 : 3 : 6 : 13 : 2.34 35 : 58 : 67 : 77 : 81 : 86 : 91 32 = 30 // 2250 : 108 : 3 : 6 : 13 : 2.40 36 : 60 : 69 : 79 : 84 : 88 : 93 31 = 33 // 2200 : 111 : 3 : 6 : 13 : 2.47 37 : 61 : 71 : 81 : 86 : 91 : 96 30 = 37 // 2150 : 114 : 3 : 7 : 14 : 2.54 38 : 63 : 73 : 83 : 88 : 93 : 99 29 = 40 // 2100 : 114 : 3 : 7 : 14 : 2.54 38 : 63 : 73 : 83 : 88 : 93 : 99 28 = 43 // 2050 : 117 : 3 : 7 : 14 : 2.61 39 : 65 : 75 : 86 : 91 : 96 : 101 27 = 47 // 2000 : 121 : 3 : 7 : 15 : 2.69 40 : 67 : 78 : 88 : 94 : 99 : 105 26 = 51 // 1950 : 125 : 3 : 7 : 15 : 2.78 41 : 69 : 80 : 91 : 97 : 102 : 108 25 = 55 // 1900 : 129 : 4 : 8 : 16 : 2.87 43 : 71 : 83 : 94 : 100 : 106 : 111 24 = 60 // 1850 : 133 : 4 : 8 : 16 : 2.96 44 : 74 : 85 : 97 : 103 : 109 : 115 23 = 65 // 1800 : 133 : 4 : 8 : 16 : 2.96 44 : 74 : 85 : 97 : 103 : 109 : 115 22 = 68 // 1750 : 137 : 4 : 8 : 17 : 3.07 45 : 76 : 88 : 101 : 107 : 113 : 119 21 = 73 // 1700 : 142 : 4 : 8 : 17 : 3.17 47 : 79 : 92 : 104 : 111 : 117 : 123 20 = 79 // 1650 : 148 : 4 : 9 : 18 : 3.29 49 : 82 : 95 : 108 : 115 : 121 : 128 19 = 85 // 1600 : 153 : 4 : 9 : 19 : 3.42 51 : 85 : 99 : 112 : 119 : 126 : 133 18 = 92 // 1550 : 160 : 5 : 10 : 20 : 3.56 53 : 88 : 103 : 117 : 124 : 131 : 138 18 = 96 // 1500 : 160 : 5 : 10 : 20 : 3.56 53 : 88 : 103 : 117 : 124 : 131 : 138 17 = 99 // 1450 : 166 : 5 : 10 : 20 : 3.70 55 : 92 : 107 : 122 : 129 : 137 : 144 16 = 107 // 1400 : 173 : 5 : 10 : 21 : 3.86 57 : 96 : 112 : 127 : 135 : 142 : 150 15 = 115 // 1350 : 181 : 5 : 11 : 22 : 4.04 60 : 101 : 117 : 133 : 141 : 149 : 157 14 = 125 // 1300 : 190 : 5 : 11 : 23 : 4.23 63 : 105 : 122 : 139 : 148 : 156 : 165 13 = 135 // 1250 : 200 : 6 : 12 : 25 : 4.44 66 : 111 : 128 : 146 : 155 : 164 : 173 12 = 146 // 1200 : 200 : 6 : 12 : 25 : 4.44 66 : 111 : 128 : 146 : 155 : 164 : 173 11 = 151 // 1150 : 210 : 6 : 13 : 26 : 4.68 70 : 116 : 135 : 154 : 163 : 173 : 182 10 = 163 // 1100 : 222 : 6 : 13 : 27 : 4.94 74 : 123 : 143 : 162 : 172 : 182 : 192 9 = 177 // 1050 : 235 : 7 : 14 : 29 : 5.23 78 : 130 : 151 : 172 : 183 : 193 : 203 8 = 193 // 1000 : 250 : 7 : 15 : 31 : 5.56 83 : 138 : 161 : 183 : 194 : 205 : 216 7 = 211 // 950 : 266 : 8 : 16 : 33 : 5.93 88 : 148 : 171 : 195 : 207 : 219 : 231 6 = 231 // 900 : 266 : 8 : 16 : 33 : 5.93 88 : 148 : 171 : 195 : 207 : 219 : 231 5 = 237 // 850 : 285 : 8 : 17 : 35 : 6.35 95 : 158 : 184 : 209 : 222 : 234 : 247 4 = 260 // 800 : 307 : 9 : 19 : 38 : 6.84 102 : 170 : 198 : 225 : 239 : 252 : 266 3 = 287 // 750 : 333 : 10 : 20 : 41 : 7.41 111 : 185 : 214 : 244 : 259 : 274 : 288 2 = 318 // 700 : 363 : 11 : 22 : 45 : 8.08 121 : 202 : 234 : 266 : 282 : 298 : 315 1 = 355 // 650 : 400 : 12 : 25 : 50 : 8.89 133 : 222 : 257 : 293 : 311 : 328 : 346 0 = 400 // 600 : 400 : 12 : 25 : 50 : 8.89 133 : 222 : 257 : 293 : 311 : 328 : 346 0 = 400 // 550 : 444 : 13 : 27 : 55 : 9.88 148 : 246 : 286 : 325 : 345 : 365 : 385 0 = 444 // // at 1000+ rpm we use the a /8 index table, to get 19 entries, 12-31 unsigned short rpm2ccr0[] = {27, // 2350-2500 27 33, // 2300 33 37, // 2250 37 43, // 2100 43 52, // 2000 52 65, // 1850 65 79, // 1700 79 85, // 1650 85 92, // 1600 92 99, // 1500 99 115, // 1400 115 125, // 1350 125 135, // 1300 135 135, // 1275 135 148, // 1200 148 163, // 1150 163 177, // 1100 177 185, // 1080 185 193, // 1050 193 200, // 1020 200 211 // 1000 211 }; unsigned short adv = 9; unsigned short x45 = 0; void coiladvance(unsigned int c45) { // we get the number of timer clicks for the last 45 degrees of rotation, // The number of clicks determines the RPM, and the degrees of advance // which translated into the amount of timer clicks before the coil fires xtar = TAR; x45 = c45; adv = c45 >> 3; // divide ticks by 8 // if the rpm is greater than 1000, we use the table lookup if (adv < 32) { if (adv < 12) adv = 12; // don't mess up if >2500 rpm adv = adv - 12; // take out base timeadv = rpm2ccr0[adv]; CCR0 = timeadv; CCTL0 = CCIE; tar = TAR; } // for idle or cranking, we have plenty of time to compute a 2-degree advance directly // and the timing is slow enough that approximite times can be off a lot else { // we get the number of timer clicks for the last 45 degrees of rotation, // The number of clicks determines the RPM, and the degrees of advance, // dpt = c45 / 45.0; // get the number of degrees per timer tick //timeadv = (c45 / 45.0) * (45 - 2); // 45 would be TDC, we advance 2 degrees // which is c45 * 43/45, which to avoid floating point, we convert 43/45 to 60/64 // so we can divide by 64. so really this is 3 degrees advanced not 2 // to multiply by 60, we do 32 + 16 + 8 + 4 // at 200 rpm, we can overflow 16bits, so we use 32 bits unsigned long t1 = c45; unsigned long t2 = (t1 << 5); t2 = t2 + (t1 << 4); t2 = t2 + (t1 << 3); t2 = t2 + (t1 << 2); timeadv = (t2 >> 6); // now setup a timer interrupt when we hit that timer tick to fire the coil // this MUST occur before the next trigger event, since if it doesn't // we have an error, or the engine speed increased significantly right after // this trigger so our timing estimate was way off. //timeadv = timeadv - coildelay; // backup the time it takes to trigger the duraspark tar = TAR; CCR0 = timeadv; CCTL0 = CCIE; } } // // we passed a tooth/magnet // void tooth() { unsigned short rpm; currentTime = TAR; // get current counter restartTimer(); // restart from zero, don't allow interrupt unless timed out thisTime = currentTime; // get the time of the last Tach ledOff(); // Led OFF //debug data dbg[di++] = thisTime; if (di >= dbgsize) di = 0; // determine if the previous time was the missing tooth // see if thisTime is approximately double the last two // see if difference is less than 10% (we use /8 shift that is 12.5%) doubleTime = lastTime1 + lastTime2; //int diff10 = thisTime >> 3; // thisTime * .15; int diff10 = thisTime >> 2; // 25% int diff = abs(doubleTime - thisTime); if ( diff < diff10 ) { // the next one will be TDC, so we determine the timing advance // and setup the timer to fire coil number 1 // we get timing of the half of the previous 90 degrees from issing tooth // ledOn(); // Led ON lastCount = 1; coil1High(); // start the current flowing into coils 1-4 if not already started tachHigh(); coiladvance((thisTime >> 1)); lastTime2 = lastTime1; // we don't need this really lastTime1 = thisTime; } // the tooth before TDC+180 is where we must start the coil charge // if the RPM is above 1400, below that we can wait until the next tooth else if (lastCount == 3) { // the next one will be TDC+180-45, so we determine the timing advance // and setup the timer to fire coil number 2 // we get timing of the previous 45 degrees to determine advance timing //ledOn(); // Led ON lastCount = 4; rpm = thisTime >> 3; if (rpm < 21) { // faster than 1400 rpm coil2High(); // start the current flowing into coils 2-3 tachHigh(); } lastTime2 = lastTime1; lastTime1 = thisTime; } // previous was not missing tooth. // see if the next one will be TDC+180 else if (lastCount == 4) { // the next one will be TDC+180, so we determine the timing advance // and setup the timer to fire coil number 2 // we get timing of the previous 45 degrees to determine advance timing //ledOn(); // Led ON lastCount = 5; coil2High(); // start the current flowing into coils 2-3 if not already started tachHigh(); coiladvance(thisTime); lastTime2 = lastTime1; // we don't need this really lastTime1 = thisTime; } else if (lastCount == 6) { // the next one will be the missing tooth, so we can't just turn on coil charge, // as it will be double time, so we setup the timer interrupt to start the coil charge // at the same tick count as the previous 45 degrees lastCount = 7; rpm = thisTime >> 3; if (rpm < 21) { // faster than 1400 rpm // create timer interrupt when missing tooth would be so we can start the coil charge // coil1High(); // start the current flowing into coils 1-4 CCR0 = thisTime; CCTL0 = CCIE; } lastTime2 = lastTime1; lastTime1 = thisTime; } // // We should have recognized the missing tooth, hmm // just carry on like we did? or go into check mode, or failure mode? else if (lastCount == 7) { // ledOn(); // Led ON coiladvance((thisTime >> 1)); lastCount = 1; lastTime2 = lastTime1; // we don't need this really lastTime1 = thisTime; } // inbetween tooth, count it and push down the times // if we are starting up and haven't recognized the missing tooth, // OR the crank speed isn't consistent to recognize the missing tooth, // we just keep incrementing the count until we find it // and restart it back to 1 so TDC+180 will be recognized. else if (lastCount > 36) { // we've spun around 3 times, and still didn't recognizing missing tooth, // something is wrong, flash error probably lost magnet bad sensor etc // they must power cycle to try again. crankError(); } else { lastCount++; lastTime2 = lastTime1; lastTime1 = thisTime; } } // // The hall sensor interrupt on port 2.2 // interrupt (PORT2_VECTOR) p2int(void) { tooth(); // when magnet passes the sensor, p2.2 goes low P2IFG = 0; // clear handled interrupt } // // If the timer counter has overflowed, // then the crank has slowed/stopped rotating. // We must resynch to the missing tooth in this case since our timing // is no longer valid. We set lastCount to 8 so it must recognize the // missing tooth, and then restart the timer. // turn off the coils so they don't overheat if engine is stopped // interrupt (TIMERA1_VECTOR) atimer(void) { lastCount == 8; restartTimer(); coil1Low(); // stop any current flowing into coils coil2Low(); // stop any current flowing into coils tachLow(); } // // The Timer Compare interrupts to fire a coil // If lastCount == 1 then we fire coil 1 // If lastCount == 5 then we fire coil 2 // If lastCount == 6 then we start charge on coil 1 // interrupt (TIMERA0_VECTOR) a0timer(void) { CCTL0 = 0; // turn off compare interrupts if (lastCount == 1) { firecoil(1); } else if (lastCount == 5) { firecoil(2); } else if (lastCount == 7) { // missing tooth interrupt to start coil charge coil1High(); tachHigh(); } else { // this is an error and should not occur lastCount == 8; } } // // MAIN // int main(void) { int i; // cheat sheet // 0100 = 4 // 1000 = 8 // 1001 = 9 // 1010 = A // 1011 = B // 1100 = C // 1101 = D // 1110 = E // // setup the MSP430 1121 for operation // WDTCTL = WDTPW + WDTHOLD; // Stop WDT DCOCTL = 0xB0; // DCO=5, MOD=0 BCSCTL1 = 0x07; // RSEL=7 == 4Mhz P1SEL = 0x00; // P1.0-4 are I/O P1DIR = 0x0F; // P1.0 P1.1 are outputs to fire coil, P1.2 tach output, P1.3 ? P1IES = 0x00; // no interrupts for P1 P1IE = 0x00; // no interrupts for P1 P2SEL = 0x00; // P2.0-8 are I/O P2DIR = 0x0B; // P2.3 is LED output, P2.2 is tach input P2IES = 0x04; // interrupt P2.2 on high-low transition P2IE = 0x04; // use interrupts for P2.2 // init all off CCTL0 = CCTL1 = CCTL2 = 0; //P2.0,2.1 are ADC inputs A0,A1 //ADC10CTL0 = ADC10ON | ADC10SHT_3; // ADC10ON and 64x sample and hold time. //ADC10AE = 0x03; // P2.0, P2.1 ADC option select // // We have a 32Khz crystal // // start timer in continuous 0-0xFFFF mode, // timer will interrupt after 1 second if we don't reset it before then // // TACTL = TASSEL_ACLK + TACLR + TAIE + MC_CONT; // flash the LED so we know the software was running when powered up // and then leave it on until a tooth is recognized TACTL = TASSEL_ACLK + TACLR + MC_CONT; ledOn(); // Led ON tar = TAR; // wait a little bit while (tar < 0x1000) { tar = TAR; } TACTL = TASSEL_ACLK + TACLR + MC_CONT; ledOff(); // Led Off tar = TAR; while (tar < 0x1000) { tar = TAR; } ledOn(); // now leave it on // now setup timer for use. restartTimer(); // // Have Watchdog Reset if we get stuck somewhere after 8ms ? // coil1Low(); coil2Low(); tachLow(); lastCount = 8; // force missing tooth discovery WDTCTL = WDTPW + WDTHOLD; // Stop WDT IE1 |= WDTIE; // Enable WDT interrupt _EINT(); // Now Enable interrupts // // Main loop does nothing, we just wait to process the tooth interrupts while(1) { _BIS_SR(CPUOFF); // Enter LPM0 _NOP(); // Required only for C-spy } }
  21. Like
    Automate got a reaction from bluehash in panStamp switching to CC430   
    For those that are not familiar with the panStamp, currently it's an Arduino compatible "stamp" with an Atmel Atmega328P and TI CC1101 wireless radio.
     
    They have announced their next version will switch to a CC430 with Energia! Now with modified Arduino 1.5 IDE.
     
     
     
    Read more here http://www.panstamp.com/announcements/imminentfuture 

  22. Like
    Automate reacted to lalalandrus in Automobile Keyless Entry   
    In this day and age, we should not need to use any keys or buttons. I have done away with the key remote in my car using this simple setup. I came to the same conclusion as this gentlemen in using the apple nike+ sensor to provide a proximity sensor to the car. 
     
    https://www.sparkfun.com/tutorials/135
     
    His code lacks a couple things that I was looking for.
    1) decoding of the apple serial protocol so that i can use any NRF module
    2) detection of when to stop strobing the remote (when the key is inserted)
    3) ability to open the trunk
     
    and since I can detect when the key is inserted, I can do other things when the car is on like strobing the garage door opener, 
     
    To accomplish 1, I found that some genius went about decoding the modules to be decoded with NRF modules
     
    http://dmitry.gr/index.php?r=05.Projects&proj=05.%20Nike%20plus%20iPod
     
    Also helping this along was energia and the already written NRF24 library. 
     
    notes about my design and things I learned:
     
    - my design is based all on a repeating 10ms timer which is a good base for modifying this code to work for different scenarios
    - i am a fpga designer and some of the code is not as efficient as a c++ programmer would make it 
    - one could optimize the interrupt routine to use less time by using a global counter and variables to store offsets rather than individual counters
    - my mazda remote is active low so the signals had to be inverted
    - i tapped into my car through the mazda  keyless module. 12v and gnd is provided. an additional signal which pullses low at a 1khz rate when there is no key inserted, it is high when a key is inserted, this powers "car timeout"
    - i originally had everything on one board, but it seemed there was too much interference for the NRF to pick up the sensor properly 
    - since there were a lot of rf devices decoupling capacitors was very necessary. 
    - there is a 24 second timeout before my car relocks if there is no door opened, i kludged a single button press keep alive  every 20 seconds using delays :-( i dont like using delays they seems so unclean.... an upgrade would be to use the -64dbm to detect that you are actually in the car and stop the strobing, ymmv and i have not implemented this (RPD register 0x09 bit 0) UPDATE: IMPLEMENTED IN NEWEST CODE
    - whenever the key is in the car, the car will cycle every ~2.5 seconds through the two parkade doors. the remote will auto shutdown if it detects a constant press so i have added a remote_pause to prevent this
    - the trunk has another msp430 performing capsense on the key hole and will activate another nike+ sensor to open the trunk. i am in the process of upgrading the sensitivity of this using swept frequency capacitive touch which i will share once i get the kinks out 
    - a cheap chinese buck module was used to reducethe voltage from 12v to 3.3v
    - replace the *_sn vectors with whatever your nike+ sensor serial number is 
    - avoid RF like the plague, even with one side guaranteed to be working, along with some issues with SPI, it was a PITA to get working the first time




    nikerf.ino
    printf.h
  23. Like
    Automate reacted to mbeals in a simple Command Stack   
    I'm working on a project that is going to involve a device relaying out sensor data while also listening for incoming commands all over UART.  To keep it mostly asynchronous, I decided to write a simple command stack structure.
     
    The idea came from the way you typically receive data over the UART...one character at a time.  The usual formula is to keep reading characters into a buffer until you hit a delimiter, then set a flag to tell the state machine to process the buffer as a command...however this approach blocks the UART, as you have to wait for the state machine to at least copy the command off somewhere before you can allow more data to be written, otherwise the command is corrupted.  Another situation would be a wireless uart, where (power wise) it is better to wake the radio up and send a burst of traffic then put it to sleep, instead of letting the data trickle out.
     
    The stack is composed of a stack of buffers.  One buffer is considered the 'active' buffer, and is the one that is actively written to.  Once a full command is written to the active buffer, it is 'committed', which flags the buffer as ready to be processed and moves on to the next buffer in the stack to start writing again.  In this fashion, you can store a whole list of commands and process them how you see fit, when you see fit.  Each buffer also has an associated 'status' flag, that currently indicates when a buffer is 'ready' to be processed and when a buffer has been overflowed (so the processing code can handle the error), but this can be extended to add other features like command priority.
     
    The basic stack structure looks like this:
    typedef struct { char buffer[STACK_LEN][BUFFER_LEN + 1]; //buffer data store. uint8_t status[STACK_LEN]; // 0x1 = process status; 0x2 = overflow status uint8_t stack_index; //which buffer are we writing to uint8_t buffer_index[STACK_LEN]; //which element of the buffer }command_stack; the meat of the stack is a 2D char array.  The data is organized into  <STACK_LEN> buffers, each <BUFFER_LEN +1> long...the +1 is to allow the buffer to be silently zero terminated.  The idea is that this structure keeps track of itself so the processing code doesn't have to.
     
    'stack_index' indicates which buffer should be written to.
     
    'buffer_index' keeps track of which index in each buffer is the 'end' of the buffer.  Since this acts as a ring buffer, buffers are just overwritten.  Clearing the buffer just involves resetting buffer_index to 0. 
     
    'status' keeps track of the status of each buffer.  Currently there are two implemented options:  the first bit is the 'process status' flag, which indicates if the buffer is ready to be read and processed by other code.  the second is an 'overflow' or 'error' flag.  As data are written to the buffers, if the buffer is overflowed, it just stops writing and sets the overflow flag.  This lets the processing code check and handle the condition gracefully.
     
    To avoid posting a huge® wall of text, I will just cover the basic usage and leave the source up on github:  https://github.com/mjbeals/commandStack
     
    To initialize everything, you just create a command_stack and call buffer_int():
    command_stack test_stack; buffer_init(&test_stack); This creates the stack and initializes it to default values (all zeros).
     
    Writing data into the current active buffer can be char at a time or string at a time:
    write_char(&test_stack, 'C'); write_string(&test_stack, "test"); Once a full command is written, it is time to commit it, which marks it as ready and rolls the stack to the next buffer
    commit_buffer(&test_stack); you can also advance the stack without setting it as 'ready' (in case there was an error, or the buffer should just be discarded) as well as modify the 'ready' status of any buffer
    advance_stack(&test_stack); void flag_buffer(&test_stack, 0, 1); //flag buffer 0 to READY To read back out the buffers, I currently only have two methods written.  The first will just dump out the currently active buffer.  The second will dump out any arbitrary buffer.  Since ideally we just commit a bunch of commands, then let the state machine process those that are ready (FIFO style), there is also a function to find the oldest ready buffer.
    char buffer[BUFFER_LEN+1]; //read the current 'active' buffer uint8_t num_chars = read_current_buffer(&test_stack, buffer); // find the index of the oldest 'ready' buffer and then read it int next_index; uint8_t isValid = oldest_ready(&test_stack, &next_index); uint8_t num_chars; if (isValid) { num_chars = read_buffer(&test_stack, buffer, next_index); } So using this framework, here is a simple uart interrupt handler:
    #pragma vector = USCIAB0RX_VECTOR __interrupt void USCI0RX_ISR(void) { char data = UCA0RXBUF; //Copy from RX buffer, in doing so we ACK the interrupt as well write_char(&rx_stack,data); //if it is a line term char, roll the stack if(data == 0x0D) commit_buffer(&rx_stack); } This will just sit there and fill the stack with commands delimited by 0x0D (it's what XBee radios use for their AT commands, which is the heart of this code).
     
     
    then with a function like:
    int8_t oldest_RX(char* buf) { uint8_t index; // if there is no buffer flagged 'ready', return 0 int8_t ready = oldest_ready(&rx_stack, &index); if (ready == 0) return 0; //read the command off the buffer into 'buf' and mark the buffer processed read_buffer(&rx_stack, buf, (uint8_t) index); flag_buffer(&rx_stack, index, 0); return 1; } the state machine can just 
    int rxstat = 0; char buffer[BUFFER_LEN+1]; while(1) { rxstat = oldest_RX(buffer); //if there is a buffer to process, rxstat = 1, command in buffer //if there is an item on the stack to process if (rxstat) { process_command(buffer); //arbitrary function to process the command } } The github repo also has sample UART code with this integrated.  A basic main loop to loop back received serial data is:
    char buffer[BUFFER_LEN+1]; int rxstat = 0; while(1) { rxstat = oldest_RX(buffer); //if there is an item on the stack to process if (rxstat) { //queue up the incoming command back to the TX stack and send enque_buffer(buffer); process_tx(1); } } It uses some of the new functions I wrote for the uart that I didn't discuss.  They are documented in source, but I may write them up later once I have a chance to refine them.
     
    As it stands, the code works for the test cases I've run, but it is in very alpha stage still.  I'm going to be refining it and adding on to it over the next few weeks especially as I wrap up this project.  One of the first additions is for the 'advance_stack' function to roll to the next (oldest) buffer that does not have a 'ready flag'.
     
    I'm completely open to comments, questions, criticism, etc.  I'm hoping to turn this into my 'go to' library for handling serial on the MSP's as I seem to find myself rewriting things from scratch each time I want to use a UART.
     
     
     
  24. Like
    Automate reacted to jazz in MSP430F550x based logic analyzer   
    My rule for uc based measuring devices, is fast (sampling) and simple (zero parts if it is possible) realization. Result is here, under 0.1 us resolution, no extra parts, just basic MSP430F550x board, powered by USB from PC.

    Logic signal is from PCM2707 3.3V USB to I2S audio bridge. By default word select frequency is 48 kHz (P1.2), and clock is 64 * 48 kHz =  3.072 MHz (P1.1).
     

  25. Like
    Automate reacted to RamonFried in New Stack exchange Embedded Programming and Design Q&A site   
    Everyone here probably knows Stack overflow, and the concept of the Q&A Stack exchange networks brings,
    We've decided to create a new dedicated site for Embedded developement, for MSP430 and other micro-controllers,
    I invite you all to register for your support in such a site here
     
    Warm regards,
    Ramon.
     
×
×
  • Create New...