Jump to content
43oh

terjeio

Members
  • Content Count

    145
  • Joined

  • Last visited

  • Days Won

    27

Reputation Activity

  1. Like
    terjeio got a reaction from veryalive in I2C interface for 4x4 keyboard   
    I2C interface for 4x4 keyboard with partial support for 2-key rollover and autorepeat. Based on a Texas Instruments MSP430G2553 processor, uses a GPIO pin for signalling keypress events to host. Example PCB is a KiCad project for the 20-pin DIP version MSP430G2553.
    https://github.com/terjeio/I2C-interface-for-4x4-keyboard
    I am using this to test jogging in my GRBL-port embedded in the CO2-laser controller firmware (for Tiva C) I am working on. I have left some code (#defined out) to show how 2-key rollover and autorepeat can be enabled for some keys. The hardware abstracted ARM GRBL-port and an example driver for the Tiva C LauncPad is also available on GitHub.
  2. Like
    terjeio got a reaction from Fmilburn in What are you doing right now..?   
    "On the edge" - I finally got around to port the latest GRBL version (1.1f) to ARM, in the process HALifying and making a library out of it. I then integrated it into my Tiva C based CO2-laser controller card codebase - next step is to hook it up to the laser proper to verify everything is working outside the test setup.
     
    I have to spend some time to learn git - currently I use Subversion for source control, running on my local server. I will not swich to git, Subversion works great for me, but for making code available to the community git is the way forward?
     
    Implementing a HAL-driver should be relatively straightforward, the core GRBL code in my port is nearly 100% hardware agnostic and all hardware related code can reside in one file (the HAL - Hardware Abstraction Layer).
     
    A preliminary version of my port can be found in the tread  "Portability Experiments (ARM M4)" over at  https://github.com/gnea/grbl/issues
     

     
    Test rig, from the edge...
     
    Terje
  3. Like
    terjeio got a reaction from Fmilburn in Query about internal rtc and writing integers to flash in msp430f5529   
    A Google search - and I found this: https://github.com/fmilburn3/RTClib
    I find solutions for most of the questions I have by searching - if that fails then the manuals are great. This processor even has driverlib support it seems.
  4. Like
    terjeio got a reaction from Fmilburn in Button Interrupt   
    Maybe wrong processor selected?
    Will it work if you remove #include <driverlib/rom.h>?, I believe that will force the linker to link the complete library functions into your program - IIRC when using the ROM version only a dispatch table and some stubs are added. If this does not help you may copy the GPIOIntRegister implementation into your code...
  5. Like
    terjeio got a reaction from Frida in Issue with transforming from port2 to port1   
    @@NurseBob Sure have to do that, from table 8.2 in the user guide:
     
    "Port Select P2SEL 02Eh Read/write 0C0h with PUC"
     
    0Ch means pins 6 and 7 are configured for primary peripheral module function on power up, not i/o.
  6. Like
    terjeio got a reaction from Fmilburn in MSP430 Infrared Controlled Wearable   
    Ok, here we go - @@Fmilburn it is not my code, I have just "translated" it from assembly to C - I have to admit I did not understand much when I started coding for MCUs...
    In my application the processor is running at 1MHz, timing parametes (BIT_50 and BIT_75) must be adjusted different.
     
    The header file:
    // // Philips RC-5 IR protocol decoder library for MSP340G2553 // #include <msp430.h> #include <stdint.h> #include <stdbool.h> // The following bit timings are for a 1MHz clock #define BIT_50 890 // 890 #define BIT_75 1348 // 1348 #define IRDATA BIT2 // IR receiver input (P1) void initRC (void); void startRC (void); uint8_t getAddress (void); uint8_t getCommand (void); bool getToggle (void); Functions:
    // // Philips RC-5 IR protocol decoder library for MSP340G2553 // // Adapted from assembly code published in Texas Instruments Application Report SLAA134 // http://www.ti.com/litv/pdf/slaa134 // // by Terje Io // #include "rc5recv.h" static volatile uint8_t count; static volatile uint16_t data; // returns device address (5 bits) uint8_t getAddress (void) { return count == 0 ? (data >> 6) & 0x1F : 0; } // returns device command (6 bits) uint8_t getCommand (void) { return data & 0x3F; } // returns toggle status - changes when a new remote key is pressed or a key is pressed, released and pressed again bool getToggle (void) { return (data & 0x800) != 0; } // Init input pin and Timer 0 void initRC (void) { P1DIR &= ~IRDATA; P1SEL |= IRDATA; TA0CTL = TASSEL_2|MC1|TACLR|TAIE; } // Start receiving data - call must be followed by LPM0 in main code (to wait for command) void startRC (void) { data = 0; count = 14; TA0CCTL1 = CM1|SCS|CAP|CCIE; } #pragma vector = TIMER0_A1_VECTOR; void __interrupt TimerA0 (void) { switch(__even_in_range(TAIV, 14)) { case 0: break; // No interrupt case 2: // CCR1 not used #ifdef DEBUG P1OUT ^= DEBUG_PIN; #endif if(TA0CCTL1 & CAP) { TA0CCTL2 = 0; TA0CCTL1 = CCIE; TA0CCR1 += BIT_75; } else if(--count == 0) { TA0CCTL1 = 0; if(data & 0x1000) { // second startbit ok? data &= 0xFFF; LPM0_EXIT; } else startRC(); } else { data = data << 1; data |= (TA0CCTL1 & SCCI) >> 10; TA0CCTL1 = CM1|CM0|SCS|CAP|CCIE; TA0CCR2 = TA0CCR1 + BIT_50; TA0CCTL2 = CCIE; } #ifdef DEBUG P1OUT ^= DEBUG_PIN; #endif break; case 4: // Handle overruns by resetting TA0CCTL2 = 0; startRC(); break; default: break; } } Snippet from my application showing usage:
    startRC(); // set up IR receiver for next message while(1) { LPM0; toggled = toggle != getToggle(); toggle = getToggle(); if((address = getAddress()) == 16) { switch(getCommand()) { case 0: selectBtn(PHONO); if(isMuted()) // If muted then selectBtn(MUTE); // demute break; ... case 12: if(toggled) selectBtn(STDBY); break; case 13: if(toggled) selectBtn(MUTE); break; ... } } if(address != 0) // if IR receiver command processed startRC(); // set it up for next message } } I have code (and schematics) for a RC5 transmitter based on MSP430G2312 as well, again based on someone elses work but cannot remember where I found it. I run it off a CR2025 cell so it has limited range (4-5m), still battery life is 1 year+ with my (daily) use.
  7. Like
    terjeio got a reaction from zeke in MSP430 Infrared Controlled Wearable   
    SLAA134 may also be of interest:
     
    http://www.ti.com/litv/pdf/slaa134
     
    I have recoded the RC5 receiver algoritm in C (for CCS) - I like it because it does not use much RAM.
    I can post the code but I need to make it postable first - it is part of one of my very first MCU projects.
     
    Terje
  8. Like
    terjeio got a reaction from Fmilburn in MSP430 Infrared Controlled Wearable   
    SLAA134 may also be of interest:
     
    http://www.ti.com/litv/pdf/slaa134
     
    I have recoded the RC5 receiver algoritm in C (for CCS) - I like it because it does not use much RAM.
    I can post the code but I need to make it postable first - it is part of one of my very first MCU projects.
     
    Terje
  9. Like
    terjeio got a reaction from yyrkoon in Personal CNC PCB routers   
    I agree with greeg too, I did not even try to mill PCBs even if I own a CNC mill - dismissed out of hand due to poor resolution,  cumbersome setup and involved workflow. However, for single sided designs I am very happy with my laser exposer now that I have mastered the process.
     

     
    This PCB took 1h30min to make from plotting (from KiCad) to developed soldermask. It then needs one hour in the reflow oven for "hardening" the soldermask before drilling and milling the edges  (I am using Mach3 for my mill). The soldermask is not perfect - most likely due to it beeing way past it "best before" date. BTW the footprint in the middle is for a 2553.
     
    "Inexpensive"? - for me, yes - as I make quite a few one-offs and small runs (typically < 5).
  10. Like
    terjeio got a reaction from bluehash in Who is using rPI ?   
    I'm going to use the latest I aquired in my new build, a 3D printer. Will be running Octoprint.
     
    Others are running OSMC, a multimedia player, and RiscOS.
     

     
     
     
     
  11. Like
    terjeio got a reaction from Fmilburn in Who is using rPI ?   
    I'm going to use the latest I aquired in my new build, a 3D printer. Will be running Octoprint.
     
    Others are running OSMC, a multimedia player, and RiscOS.
     

     
     
     
     
  12. Like
    terjeio got a reaction from yyrkoon in gpio interrupts   
    The standard Windows calculator in Programmer mode (Alt+3) is quite handy too...
  13. Like
    terjeio reacted to greeeg in gpio interrupts   
    Isn't this still producing the wrong result??
     
    After negating , if you add you'll get an overflow....
    (~BIT0) + (~BIT5) == (~0x01) + (~0x20) == (0xFE) + (0xDF) == (0x1DD) If you insist on negating within brackets then you should be using AND operations to receive the required result, not ADD.
    (~BIT0) & (~BIT5) == (~0x01) & (~0x20) == (0xFE) & (0xDF) == (0xDE)
  14. Like
    terjeio reacted to will in Temperature & Humidity sensor -with LCD & RF   
    Hi everyone, this is my credit card size wireless sensor node,
    with a 7-seg LCD display showing temperature & humidity, update every second.
    using MSP430FR4133 with HDC1080,BMP180 and OPT3002, 
    transmit by nRF24l01, which sends out temp,humid,pressure,luminosity and also battery voltage per minute.
     

     
    It is all power by a CR2032, and thanks to MSP430FR4133, I can manage to have half an year battery life.

    also thanks to MSP430RF4133 Launchpad with build-in energyTrace, I can estimate battery life with a click(no more oscilloscope  )

    note that I've actually put an RF430 on the down left ot the board(there is an antenna for that),
    which will act as a NFC tag, but it draws too much current (~15uA), so I took it off
    and at the down right is the battery voltage measurement with a mosfet to cut the power,
    but I found out that I can just measure internal voltage reference to calculate its supply voltage, so I've also remove that. 

     
    although I'm pretty much satisfy with this power consumption, but I still think that 16.5uA is a little bit too far from estimating from datasheet
    and I am still trying to figure that out
  15. Like
    terjeio got a reaction from Fmilburn in MSP430 with VS1838B   
    @@SimpleThings : did you manage to get this working? I have just added support for some Samsung TV remote commands for my multimedia center and came to think of your problem again. When I started experimenting with IR remote control I bought a similar remote but I quicly abandoned it because of its flimsy mechanical design and went for my own - both transmitter and receiver (MSP430 based). Another problem was the limited memory, I think the arduino library uses quite a bit for buffering the intra-timing between pulses. This may well be your problem - at least if you are using a MSP430 with 512 bytes of memory or less. I worked around this by converting some assembly code to C for the RC5 protocol. However, I think this code is not useful for the Chinese remotes as AFAIK they do use this protocol.
     
    Anyway, here it is:
    // // Philips RC-5 decoder library // // Inspired by Texas Instruments Application Report SLAA134 // #include <msp430.h> #include "rc5recv.h" static volatile int count, data; unsigned int getAddress(void) { return count == 0 ? (data >> 6) & 0x1F : 0; } unsigned int getCommand(void) { return data & 0x3F; } unsigned int getToggle(void) { return (data & 0x800) != 0; } void initRC (void) { P1DIR &= ~IRDATA; P1SEL |= IRDATA; TA0CTL = TASSEL_2|MC1|TACLR|TAIE; } void startRC (void) { data = 0; count = 14; TA0CCTL1 = CM1|SCS|CAP|CCIE; } #pragma vector = TIMER0_A1_VECTOR; void __interrupt TimeA0 (void) { switch(__even_in_range(TAIV,14)) { case 0: break; // No interrupt case 2: // CCR1 not used #ifdef DEBUG P1OUT ^= DEBUG_PIN; #endif if(TA0CCTL1 & CAP) { TA0CCTL2 = 0; TA0CCTL1 = CCIE; TA0CCR1 += BIT_75; } else if(--count == 0) { TA0CCTL1 = 0; if(data & 0x1000) { // second startbit ok? data &= 0xFFF; LPM0_EXIT; //? } else startRC(); } else { data = data << 1; data |= (TA0CCTL1 & SCCI) >> 10; TA0CCTL1 = CM1|CM0|SCS|CAP|CCIE; TA0CCR2 = TA0CCR1 + BIT_50; TA0CCTL2 = CCIE; } #ifdef DEBUG P1OUT ^= DEBUG_PIN; #endif break; case 4: // Handle overruns by resetting // P1OUT |= GREEN; TA0CCTL2 = 0; startRC(); break; case 6: break; // reserved case 8: break; // reserved case 10: break; // reserved case 12: break; // reserved case 14: break; // overflow not used default: break; } } // // Philips RC-5 decoder library header // // #define BIT_50 890 // 890 (1246) #define BIT_75 1348 //1348 #define IRDATA BIT2 // IR receiver input (Port 1) void initRC(void); void startRC(void); unsigned int getAddress(void); unsigned int getCommand(void); unsigned int getToggle(void);
  16. Like
    terjeio got a reaction from SimpleThings in MSP430 with VS1838B   
    VS1838B should work with MSP as it supports a VCC range of 2.7 to 5.5V. For Energia you need both the header file and the library code as well, I do not know if it can be used directly or must be adapted for MSP first.
     
    I think the source is found here: https://github.com/z3t0/Arduino-IRremote/wiki/Receiving-with-the-IRremote-library
     
    For finding out the codes transmitted this may be of use: https://github.com/z3t0/Arduino-IRremote/wiki/Receiving-with-the-IRremote-library
  17. Like
    terjeio got a reaction from agaelema in Compact command parser/dispatcher example   
    A command parser/dispatcher example from my CO2 laser engraver codebase, using a struct array containing the commands and associated  pointer to functions. A lot cleaner (and easier to maintain) than switch/case statements or if/else constructs...
    Functions get called with a pointer to the command tail for local parameter parsing.
    The struct array data are all placed in flash.
    typedef struct { char const *const command; bool (*const handler)(char *); const bool report; } command; bool query (char* params); bool start (char* params); bool moveXrel (char* params); bool moveYrel (char* params); bool moveZrel (char* params); bool XHome (char* params); bool YHome (char* params); bool ZHome (char* params); bool XYHome (char* params); bool zeroAllAxes (char* params); bool laser (char* params); bool setLaserPower (char* params); bool setImageDPI (char* params); bool setPulseDutyCycle (char* params); bool enableCoolant (char* params); bool enableAirAssist (char* params); bool setMode (char* params); bool getPosition (char* params); bool setPPI (char* params); bool setPulseWidth (char* params); bool enableExhaustFan (char* params); bool setEngravingSpeed (char* params); bool getStatus (char* params); bool setEchoMode (char* params); bool setAMode (char* params); bool setPWROffset (char* params); bool loadProfile (char* params); bool setXBcomp (char* params); void exeCommand (char *cmdline) { static const command commands[] = { "?", &query, true, "Power:", &setLaserPower, true, "DutyCycle:", &setPulseDutyCycle, true, "PulseWidth:", &setPulseWidth, true, "DPI:", &setImageDPI, true, "Start:", &start, true, "X:", &moveXrel, true, "Y:", &moveYrel, true, "Z:", &moveZrel, true, "HomeXY", &XYHome, true, "HomeX", &XHome, true, "HomeY", &YHome, true, "HomeZ", &ZHome, true, "ZeroAll", &zeroAllAxes, true, "Laser:", &laser, true, "Coolant:", &enableCoolant, true, "Air:", &enableAirAssist, true, "Mach3:", &setMode, true, "Pos", &getPosition, false, "PPI:", &setPPI, true, "Exhaust:", &enableExhaustFan, true, "Speed:", &setEngravingSpeed, true, "Status", &getStatus, false, "ASelect:", &setAMode, true, "PWROffset:", &setPWROffset, true, "LoadProfile:", &loadProfile, true, "XBComp:", &setXBcomp, true, "Echo:", &setEchoMode, false }; bool ok = false; uint32_t i = 0, numcmds = sizeof(commands) / sizeof(command), cmdlen; while(!ok && i < numcmds) { cmdlen = strlen(commands[i].command); if(!(ok = !strncmp(commands[i].command, cmdline, cmdlen))) i++; } if(ok) { ok = commands[i].handler(cmdline + cmdlen); if(commands[i].report) serialWriteLn(ok ? "OK" : "FAILED")); } else serialWriteLn("Bad command"); } For further reading see http://www.barrgroup.com/Embedded-Systems/How-To/C-Function-Pointers
     
     
     
  18. Like
    terjeio got a reaction from Rei Vilo in I   
    This is how I implemented (blocking) multi byte read on Tiva, could easily be adapted for variable length frames:
    uint8_t* I2CReceiveMany(uint32_t i2cAddr, uint32_t bytes) { // many bytes (min 2, max 8) uint8_t *data = I2CBuffer; I2CMasterSlaveAddrSet(I2C1_BASE, i2cAddr, true); I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START); while(bytes--) { while(I2CMasterBusy(I2C1_BASE)); *data++ = I2CMasterDataGet(I2C1_BASE); I2CMasterControl(I2C1_BASE, bytes ? I2C_MASTER_CMD_BURST_RECEIVE_CONT : I2C_MASTER_CMD_BURST_RECEIVE_FINISH); } return I2CBuffer; } For MSP I did this - still blocking but by sleeping, again could be adapted:
    unsigned char* I2CReceiveMany(const unsigned int bytes) { // many bytes (min 2, max 8) I2CBCount = bytes; pI2CBuffer = I2CBuffer; // TX buffer start address while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent UCB0CTL1 &= ~UCTR; // I2C start condition UCB0CTL1 |= UCTXSTT; // I2C start condition IFG2 &= ~UCB0RXIE; IE2 |= UCB0RXIE; LPM0; // Enter LPM0 w/ interrupts IE2 &= ~UCB0RXIE; // Disable interrupt and return I2CBuffer; // return result } #pragma vector=USCIAB0TX_VECTOR __interrupt void USCI0TX_ISR(void) { unsigned int tail, intr = IFG2 & IE2; // Local variables and masked interrupt flags ...some irrelevant code... } else if(intr & UCB0RXIFG) { // I2C RX if(--I2CBCount) { *pI2CBuffer++ = UCB0RXBUF; if(I2CBCount == 1) // Only one byte left? UCB0CTL1 |= UCTXSTP; // Generate I2C stop condition } else { // Finished? *pI2CBuffer = UCB0RXBUF; LPM0_EXIT; // Exit LPM0 } } } I believe your problem is that you end the transaction by generating a stop condition by reading the first byte separately, I do not know if that is possible to avoid in the Energia framework by somehow modifying a multibyte read "on-the-fly".
  19. Like
    terjeio got a reaction from timotet in Compact command parser/dispatcher example   
    A command parser/dispatcher example from my CO2 laser engraver codebase, using a struct array containing the commands and associated  pointer to functions. A lot cleaner (and easier to maintain) than switch/case statements or if/else constructs...
    Functions get called with a pointer to the command tail for local parameter parsing.
    The struct array data are all placed in flash.
    typedef struct { char const *const command; bool (*const handler)(char *); const bool report; } command; bool query (char* params); bool start (char* params); bool moveXrel (char* params); bool moveYrel (char* params); bool moveZrel (char* params); bool XHome (char* params); bool YHome (char* params); bool ZHome (char* params); bool XYHome (char* params); bool zeroAllAxes (char* params); bool laser (char* params); bool setLaserPower (char* params); bool setImageDPI (char* params); bool setPulseDutyCycle (char* params); bool enableCoolant (char* params); bool enableAirAssist (char* params); bool setMode (char* params); bool getPosition (char* params); bool setPPI (char* params); bool setPulseWidth (char* params); bool enableExhaustFan (char* params); bool setEngravingSpeed (char* params); bool getStatus (char* params); bool setEchoMode (char* params); bool setAMode (char* params); bool setPWROffset (char* params); bool loadProfile (char* params); bool setXBcomp (char* params); void exeCommand (char *cmdline) { static const command commands[] = { "?", &query, true, "Power:", &setLaserPower, true, "DutyCycle:", &setPulseDutyCycle, true, "PulseWidth:", &setPulseWidth, true, "DPI:", &setImageDPI, true, "Start:", &start, true, "X:", &moveXrel, true, "Y:", &moveYrel, true, "Z:", &moveZrel, true, "HomeXY", &XYHome, true, "HomeX", &XHome, true, "HomeY", &YHome, true, "HomeZ", &ZHome, true, "ZeroAll", &zeroAllAxes, true, "Laser:", &laser, true, "Coolant:", &enableCoolant, true, "Air:", &enableAirAssist, true, "Mach3:", &setMode, true, "Pos", &getPosition, false, "PPI:", &setPPI, true, "Exhaust:", &enableExhaustFan, true, "Speed:", &setEngravingSpeed, true, "Status", &getStatus, false, "ASelect:", &setAMode, true, "PWROffset:", &setPWROffset, true, "LoadProfile:", &loadProfile, true, "XBComp:", &setXBcomp, true, "Echo:", &setEchoMode, false }; bool ok = false; uint32_t i = 0, numcmds = sizeof(commands) / sizeof(command), cmdlen; while(!ok && i < numcmds) { cmdlen = strlen(commands[i].command); if(!(ok = !strncmp(commands[i].command, cmdline, cmdlen))) i++; } if(ok) { ok = commands[i].handler(cmdline + cmdlen); if(commands[i].report) serialWriteLn(ok ? "OK" : "FAILED")); } else serialWriteLn("Bad command"); } For further reading see http://www.barrgroup.com/Embedded-Systems/How-To/C-Function-Pointers
     
     
     
  20. Like
    terjeio got a reaction from Fmilburn in Compact command parser/dispatcher example   
    @@zeke : I am happy that you found my post useful.
     
    My example is a relative primitive command line parser, a command line is always a string (char *) so may contain all kinds (types) of parameters. When calling the function associated with the command I pass the command tail, a pointer to the rest of the command line. It is the up to the called function to parse this and do any required sanity checking/conversions. Some command line parsers may break up the line into an array of strings, usually using space as a delimiter - argc/argv as arguments to main() is an example of that.
     
    The parseInt() function is a poor mans implementation of atoi(), it is inherited from the MSP430G2553 version of my code - atoi() uses quite a bit of RAM so is a no-no when only 512 bytes are available. Here it is:
    int32_t parseInt (char *s) { int32_t c, res = 0, negative = 0; if(*s == '-') { negative = 1; s++; } else if(*s == '+') s++; while((c = *s++) != '\0') { if(c >= 48 && c <= 57) res = (res * 10) + c - 48; } return negative ? -res : res; } Pretty primitive and does not do much sanity checking - but works...
     
    Some of my commands take two numerical parameters - comma separated, to parse them I use:
    bool start (char* params) { char *p2; uint32_t xpixels = 0, ypixels = 0; bool ok = false; if((p2 = strchr(params, ',')) != NULL) { *p2++ = '\0'; ypixels = parseInt(p2); } xpixels = parseInt(params); if(xpixels == 0 || ypixels == 0) serialWriteLn("Bad/missing parameters"); else { ... Hope this helps.
     
    Terje
  21. Like
    terjeio got a reaction from zeke in Compact command parser/dispatcher example   
    @@zeke : I am happy that you found my post useful.
     
    My example is a relative primitive command line parser, a command line is always a string (char *) so may contain all kinds (types) of parameters. When calling the function associated with the command I pass the command tail, a pointer to the rest of the command line. It is the up to the called function to parse this and do any required sanity checking/conversions. Some command line parsers may break up the line into an array of strings, usually using space as a delimiter - argc/argv as arguments to main() is an example of that.
     
    The parseInt() function is a poor mans implementation of atoi(), it is inherited from the MSP430G2553 version of my code - atoi() uses quite a bit of RAM so is a no-no when only 512 bytes are available. Here it is:
    int32_t parseInt (char *s) { int32_t c, res = 0, negative = 0; if(*s == '-') { negative = 1; s++; } else if(*s == '+') s++; while((c = *s++) != '\0') { if(c >= 48 && c <= 57) res = (res * 10) + c - 48; } return negative ? -res : res; } Pretty primitive and does not do much sanity checking - but works...
     
    Some of my commands take two numerical parameters - comma separated, to parse them I use:
    bool start (char* params) { char *p2; uint32_t xpixels = 0, ypixels = 0; bool ok = false; if((p2 = strchr(params, ',')) != NULL) { *p2++ = '\0'; ypixels = parseInt(p2); } xpixels = parseInt(params); if(xpixels == 0 || ypixels == 0) serialWriteLn("Bad/missing parameters"); else { ... Hope this helps.
     
    Terje
  22. Like
    terjeio got a reaction from zeke in Compact command parser/dispatcher example   
    @@zeke - converting code from switch/case statements is just creating a function of/for each case: ... break; block with signature as defined for the handler in the command struct. The handler signature can of course be changed to suit your needs.
     
    Another use of pointer to functions is for implementing a HAL (Hardware Abstraction Layer), I am going to use that approach in my port of Grbl to Tiva C. I find using #defines in the main code (as it stands now) makes it messy and hard to read and modify - using function pointers instead clearly defines the signatures of the functions to be implemented and there is (in theory) no need to change the main code for a new HAL/processor implementation.
     
    This is my current HAL structure for Grbl:
    typedef struct { void (*initMPU)(struct HAL *hal); void (*releaseMPU)(void); void (*serial_write)(uint8_t data); uint8_t (*serial_read)(void); void (*limits_disable)(void); uint8_t (*limits_get_state)(void); void (*coolant_stop)(void); void (*coolant_set_state)(uint8_t mode); void (*delay_ms)(uint16_t ms); void (*delay_us)(uint32_t us); uint8_t (*probe_get_state)(uint8_t probe_invert_mask); void (*spindle_stop)(void); void (*spindle_set_state)(uint8_t state, float rpm); uint8_t (*system_check_safety_door_ajar)(void); void (*stepper_wake_up)(uint8_t pulse_time); void (*stepper_go_idle)(void); void (*stepper_disable)(uint8_t state); void (*stepper_set_outputs)(uint8_t step_outbits); void (*stepper_set_directions)(uint8_t dir_outbits); void (*stepper_cycles_per_tick)(uint16_t cycles_per_tick); void (*stepper_pulse_time)(uint8_t cycles_per_tick); uint8_t (*uart_receive_data)(void); void (*uart_send_data)(uint8_t data); void (*uart_int_enable)(bool on); // callbacks - set up by library before MCU init uint8_t (*stepper_driver_interrupt_callback)(void); uint8_t (*stepper_reset_interrupt_callback)(void); uint8_t (*stepper_delay_interrupt_callback)(void); void (*limit_interrupt_callback)(void); void (*control_interrupt_callback)(uint8_t pin); settings_t *settings; } HAL; IIRC TIs graphics library has implemented the driver HAL in the same/similar way.
  23. Like
    terjeio got a reaction from zeke in Compact command parser/dispatcher example   
    @@zeke - ok I'll try, here is the setEchoMode function as I have implemented it:
    bool setEchoMode (char* params) { echo = parseInt(params) != 0; return true; } echo is a boolean variable - command will be either "Echo:0" (off) or "Echo:1" (on - in fact any parameter value diferent from 0 will set echo to true).
    this version relies on my parseInt function, code can be simplified to:
    bool setEchoMode (char* params) {     echo = *params == '1';     return true; } with improved parameter checking and proper status return:
    bool setEchoMode (char* params) { if(*params == '1') { echo = true; return true; } else if(*params == '0') { echo = false; return true; } else return false; } I am using ":" as command/parameter separator, I have added this to the command in the command list so easy to change.
  24. Like
    terjeio reacted to bluehash in Compact command parser/dispatcher example   
    Thank you for sharing!
    Also as an FYI... Tivaware also has a similar parser, under utils/cmdline.c
  25. Like
    terjeio got a reaction from spirilis in Compact command parser/dispatcher example   
    @@zeke - ok I'll try, here is the setEchoMode function as I have implemented it:
    bool setEchoMode (char* params) { echo = parseInt(params) != 0; return true; } echo is a boolean variable - command will be either "Echo:0" (off) or "Echo:1" (on - in fact any parameter value diferent from 0 will set echo to true).
    this version relies on my parseInt function, code can be simplified to:
    bool setEchoMode (char* params) {     echo = *params == '1';     return true; } with improved parameter checking and proper status return:
    bool setEchoMode (char* params) { if(*params == '1') { echo = true; return true; } else if(*params == '0') { echo = false; return true; } else return false; } I am using ":" as command/parameter separator, I have added this to the command in the command list so easy to change.
×
×
  • Create New...