spirilis 1,265 Posted July 20, 2012 Share Posted July 20, 2012 I just had a look, it's all so clean and pretty. A whole lot better than that thing I posted. Some really fantastic work. Thanks! Docs are coming along here-- https://github.com/spirilis/msprf24/wiki ... made a lot of headway today yyrkoon and bluehash 2 Quote Link to post Share on other sites
spirilis 1,265 Posted August 15, 2012 Share Posted August 15, 2012 Update: Lost access to my dev workstation (macbook pro) for a couple weeks due to a HW issue, had it taken care of and now I'm back at it.... I did some bugfixing of the code after a comment on github and some testing of my own yesterday with an actual application. Got it reliably sending 4 integers over the wire to another LP dumping data to the serial port. First 2 int's are 0xDEAD and 0xBEEF, second 2 are 32-bits coming from a MAX31855 thermocouple amplifier. After much head-desking and eventually slapping my logic analyzer on it I realized some type casts were corrupting my data and found a workaround; now it sends packets correctly! Documentation is quite incomplete still, so I'm gonna get on that soon. Lots more to write on the github wiki for the project. Last but not least, here's the example code (G2452) I used to transmit thermocouple data: /* tcamp 2.4 - MOSFET gate (active=low) 2.5 - TCAMP SPI CS */ #include #include #include "msprf24.h" int tc[2]; volatile int wdtsleep; const int packet_preamble[] = {0xDEAD, 0xBEEF}; const char txaddr[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x01}; char buf[16]; /* Sleep for * 47ms */ void wdt_sleep(unsigned int cycles) { wdtsleep = cycles; WDTCTL = WDTPW | WDTTMSEL | WDTCNTCL | WDTSSEL | WDTIS1; // WDT interval = 512 VLOCLK cycles, about 47ms IFG1 &= ~WDTIFG; IE1 |= WDTIE; LPM3; WDTCTL = WDTPW | WDTHOLD; } void main() { char c; WDTCTL = WDTPW | WDTHOLD; DCOCTL = CALDCO_16MHZ; BCSCTL1 = CALBC1_16MHZ; BCSCTL2 = DIVS_2; // SMCLK = MCLK/4 BCSCTL3 = LFXT1S_2; // ACLK = VLOCLK/1 BCSCTL3 &= ~(XT2OF|LFXT1OF); wdtsleep = 0; // Thermocouple Amplifier PWR control, SPI CS pins P2DIR |= BIT4|BIT5; P2OUT |= BIT4|BIT5; // MOSFET P-channel gate off (set high), Chip Select disabled (set high) // P1.0 LED pin P1DIR |= BIT0; P1OUT &= ~BIT0; /* Initial values for nRF24L01+ library config variables */ rf_crc = RF24_EN_CRC | RF24_CRCO; // CRC enabled, 16-bit rf_addr_width = 5; rf_speed_power = RF24_SPEED_MIN | RF24_POWER_MIN; rf_channel = 60; msprf24_init(); msprf24_set_pipe_packetsize(0, 0); // Dynamic packet sizes msprf24_open_pipe(0, 1); // Open pipe#0 with Enhanced ShockBurst for receiving Auto-ACKs /* Main loop */ while (1) { P2OUT &= ~BIT4; // Activate TCAMP P-channel MOSFET // Wait 235ms for thermocouple amplifier to power up & do a successful conversion wdt_sleep(5); // Read TC amplifier P2OUT &= ~BIT5; // TCAMP CS active tc[0] = spi_transfer16(0x0000); tc[1] = spi_transfer16(0x0000); P2OUT |= BIT5; // TCAMP CS inactive P2OUT |= BIT4; // Shut off TCAMP P-channel MOSFET // Compose nRF message for (c=0; c<16; c++) buf[c] = '\0'; memcpy(buf, &packet_preamble, sizeof(int)*2); memcpy(buf+sizeof(int)*2, &tc, sizeof(int)*2); // Online the nRF24L01+ transceiver msprf24_standby(); flush_tx(); w_tx_addr( (char*)txaddr ); w_rx_addr(0, (char*)txaddr ); w_tx_payload(sizeof(int)*4, buf); msprf24_activate_tx(); LPM4; if (RF24_IRQ_FLAGGED & rf_irq) { rf_irq &= RF24_IRQ_FLAGGED; msprf24_get_irq_reason(); if (rf_irq & RF24_IRQ_TX) P1OUT &= BIT0; // Successful TX, clear red LED if (rf_irq & RF24_IRQ_TXFAILED) P1OUT |= BIT0; // Unsuccessful TX, set red LED msprf24_irq_clear(RF24_IRQ_MASK); } msprf24_powerdown(); // Put the RF transceiver back to sleep wdt_sleep(21); // Sleep for ~1 second } } // WDT overflow/STOP #pragma vector=WDT_VECTOR __interrupt void WDT_ISR(void) { if (wdtsleep) { wdtsleep--; } else { IFG1 &= ~WDTIFG; IE1 &= ~WDTIE; __bic_SR_register_on_exit(LPM3_bits); } } The nrf_userconfig.h for the G2452 TC amplifier transmitter- /* nrf_userconfig.h * User configuration of nRF24L01+ connectivity parameters, e.g. * IRQ, CSN, CE pin assignments, Serial SPI driver type * * * Copyright (c) 2012, Eric Brundick * * Permission to use, copy, modify, and/or distribute this software for any purpose * with or without fee is hereby granted, provided that the above copyright notice * and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _NRF_USERCONFIG_H #define _NRF_USERCONFIG_H /* CPU clock cycles for the specified amounts of time--accurate minimum delays * required for reliable operation of the nRF24L01+'s state machine. */ /* Settings for 1MHz MCLK. #define DELAY_CYCLES_5MS 5000 #define DELAY_CYCLES_130US 130 #define DELAY_CYCLES_10US 10 */ /* Settings for 16MHz MCLK */ #define DELAY_CYCLES_5MS 80000 #define DELAY_CYCLES_130US 2080 #define DELAY_CYCLES_10US 160 /* SPI port--Select which USCI port we're using. * Applies only to USCI devices. USI users can keep these * commented out. */ //#define RF24_SPI_DRIVER_USCI_A 1 //#define RF24_SPI_DRIVER_USCI_B 1 /* Define whether this library should use LPM0+IRQs during SPI I/O and whether this library should provide the ISR. */ //#define RF24_SPI_DRIVER_USCI_USE_IRQ 1 //#define RF24_SPI_DRIVER_USCI_PROVIDE_ISR 1 /* Operational pins -- IRQ, CE, CSN (SPI chip-select) */ /* IRQ */ #define nrfIRQport 2 #define nrfIRQpin BIT0 /* CSN SPI chip-select */ #define nrfCSNport 2 #define nrfCSNportout P2OUT #define nrfCSNpin BIT1 /* CE Chip-Enable (used to put RF transceiver on-air for RX or TX) */ #define nrfCEport 2 #define nrfCEportout P2OUT #define nrfCEpin BIT2 #endif Receiver code (G2553): #include #include #include "msprf24.h" #include "uart.h" volatile int wdtsleep; const char rxaddr[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x01}; const char* digits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}; // For easy printing. /* Sleep for * 47ms */ void wdt_sleep(unsigned int cycles) { wdtsleep = cycles; WDTCTL = WDTPW | WDTTMSEL | WDTCNTCL | WDTSSEL | WDTIS1; // WDT interval = 512 VLOCLK cycles, about 47ms IFG1 &= ~WDTIFG; IE1 |= WDTIE; LPM3; WDTCTL = WDTPW | WDTHOLD; } void dump_packet(char *buf, char len) { int i; for (i=0; i uart_print( (char*)digits[(buf[i] & 0xF0) >> 4] ); uart_print( (char*)digits[buf[i] & 0x0F] ); uart_print(" "); } uart_print("\n"); } char buf[16]; void main() { char c; int pa[2]; WDTCTL = WDTPW | WDTHOLD; DCOCTL = CALDCO_16MHZ; BCSCTL1 = CALBC1_16MHZ; BCSCTL2 = DIVS_2; // SMCLK = MCLK/4 BCSCTL3 = LFXT1S_2; // ACLK = VLOCLK/1 BCSCTL3 &= ~(XT2OF|LFXT1OF); wdtsleep = 0; uart_init(); // P1.0 LED pin P1DIR |= BIT0; P1OUT &= ~BIT0; /* Initial values for nRF24L01+ library config variables */ rf_crc = RF24_EN_CRC | RF24_CRCO; // CRC enabled, 16-bit rf_addr_width = 5; rf_speed_power = RF24_SPEED_MIN | RF24_POWER_MIN; rf_channel = 60; msprf24_init(); if (msprf24_current_state() == RF24_STATE_NOTPRESENT) { P1OUT |= BIT0; // Set red LED _DINT(); LPM4; // Halt completely } msprf24_set_pipe_packetsize(0, 0); // Dynamic packet sizes msprf24_open_pipe(0, 1); // Open pipe#0 with Enhanced ShockBurst for receiving Auto-ACKs // Initialize RF receiver w_rx_addr(0, (char*) rxaddr); msprf24_activate_rx(); /* Main loop */ while (1) { if (!(RF24_IRQ_FLAGGED & rf_irq)) // Catch additional incoming packets that may have come in during UART writing wdt_sleep(42); // No pending packets? Sleep for ~2sec // Note: wdt_sleep stops the WDT timer after waking from LPM3, so no WDT IRQs should fire until we run // wdt_sleep() again. if (RF24_IRQ_FLAGGED & rf_irq) { // We woke up due to an incoming transmission, not the WDT sleep. // Address the IRQ rf_irq &= ~RF24_IRQ_FLAGGED; msprf24_get_irq_reason(); if (RF24_IRQ_RX & rf_irq) { if ( (c = r_rx_peek_payload_size()) != sizeof(int)*4 ) { flush_rx(); msprf24_irq_clear(RF24_IRQ_MASK); // Clear IRQ uart_begin(); uart_print("RX payload size "); uart_print( (char*)digits[c/10] ); uart_print( (char*)digits[c - (c/10)*10] ); uart_print(" not correct.\n"); uart_end(); } else { r_rx_payload(c, buf); msprf24_irq_clear(RF24_IRQ_MASK); // Clear IRQ uart_begin(); uart_print("Reading "); uart_print( (char*)digits[c/10] ); uart_print( (char*)digits[c - (c/10)*10] ); uart_print(" bytes from RX FIFO...\n"); dump_packet(buf, c); memcpy(pa, buf, sizeof(int)*2); if ( pa[0] != 0xDEAD || pa[1] != 0xBEEF ) { uart_begin(); uart_print("Packet preamble does not match 0xDEADBEEF\n"); uart_end(); } else { uart_begin(); uart_print("Thermocouple data: 0x"); uart_print( (char*)digits[(buf[5] & 0xF0) >> 4] ); uart_print( (char*)digits[(buf[5] & 0x0F)] ); uart_print( (char*)digits[(buf[4] & 0xF0) >> 4] ); uart_print( (char*)digits[(buf[4] & 0x0F)] ); uart_print( (char*)digits[(buf[7] & 0xF0) >> 4] ); uart_print( (char*)digits[(buf[7] & 0x0F)] ); uart_print( (char*)digits[(buf[6] & 0xF0) >> 4] ); uart_print( (char*)digits[(buf[6] & 0x0F)] ); uart_print("\n"); uart_end(); } } } else { // Just clear the IRQ and ignore what it meant (we only care about RX, and should only be receiving RX IRQs!) // i.e. this section should never actually execute... msprf24_irq_clear(RF24_IRQ_MASK); } } else { // wdt_sleep completed, no data came in uart_begin(); uart_print("No thermocouple data for 2 seconds...\n"); uart_end(); } } } // WDT overflow/STOP #pragma vector=WDT_VECTOR __interrupt void WDT_ISR(void) { if (wdtsleep) { wdtsleep--; } else { IFG1 &= ~WDTIFG; IE1 &= ~WDTIE; __bic_SR_register_on_exit(LPM3_bits); } } Just in case anyone's curious, the "uart.c" code I cooked up (could've used other examples, wanted to get my feet wet though): #include #include #include void uart_init() { // Init USCI, leave in RESET mode. // Assumes SMCLK = MCLK/4 (4MHz) IFG2 &= ~(UCA0TXIFG | UCA0RXIFG); UCA0CTL0 = 0x00; UCA0CTL1 = UCSSEL_2 | UCDORM | UCSWRST; UCA0BR0 = 26; UCA0BR1 = 0; UCA0MCTL = UCBRS_0 | UCBRF_1 | UCOS16; P1SEL = BIT1|BIT2; // USCIA P1SEL2 = BIT1|BIT2; } void uart_begin() { UCA0CTL1 &= ~UCSWRST; IE2 |= UCA0TXIE; } void uart_end() { //UCA0CTL1 |= UCSWRST; // doing this after every block added some glitch to the output IE2 &= ~UCA0TXIE; } void uart_print(char *str) { int i=0, j; j = strlen(str); for (; j; j--) { UCA0TXBUF = str[i]; LPM0; i++; } } // USCI continue with next char #pragma vector=USCIAB0TX_VECTOR __interrupt void USCI0TX_ISR(void) { if (IFG2 & UCA0TXIFG) { IFG2 &= ~UCA0TXIFG; __bic_SR_register_on_exit(LPM0_bits); } } yyrkoon and bluehash 2 Quote Link to post Share on other sites
bluehash 1,581 Posted August 18, 2012 Share Posted August 18, 2012 Nice.. and thanks.. So it's all set and working? I'll make a blog post then. Quote Link to post Share on other sites
spirilis 1,265 Posted August 27, 2012 Share Posted August 27, 2012 Yep the library works, documentation is incomplete atm. Took a hiatus to recover from sinus troubles and now I'm back at it ... There's someone on github posting comments on one of the commits too, some of the minor code mistakes he's making underlines the need for me to add a thorough walkthrough on what the different functions do/why you need them/how to plan out your connections. Quote Link to post Share on other sites
cubeberg 540 Posted October 1, 2012 Share Posted October 1, 2012 Bought a few modules off eBay this weekend - I'll have to give this a try when they arrive. Awesome to see a bunch of work already done. Anybody do any range testing with the different antenna types? I bought two with the ? type antenna and two with the wiggle antenna. Quote Link to post Share on other sites
spirilis 1,265 Posted October 1, 2012 Share Posted October 1, 2012 I have both types now, didn't see much difference between them. I can tell you they don't work well at all through metal doors or concrete foundations ... but through typical wood stud + drywall type of walls, they work well. Quote Link to post Share on other sites
cubeberg 540 Posted October 1, 2012 Share Posted October 1, 2012 K, good to know - hopefully I'll get better range than I was with the Anaren booster. I barely got 20 feet out of those (could have been a setting I guess). Quote Link to post Share on other sites
spirilis 1,265 Posted October 1, 2012 Share Posted October 1, 2012 I've definitely got more than 20 feet, actually I had probably 40 feet with some glass/metal doors, faux-wood panelled walls between the two transceivers... I also have a powered one, meaning the $20-ish units with a PA+LNA amplifier onboard and WiFi antenna ... They work a hell of a lot better when they're acting as a transmitter, IMO, as a receiver they don't add nearly as much range. This makes sense though, since it's the signal that's getting lost by obstacles/etc... transmitting a higher power signal is probably more important than amplifying the received signal. Quote Link to post Share on other sites
spirilis 1,265 Posted November 18, 2012 Share Posted November 18, 2012 Discovered something today in the midst of debugging my grill monitor. The "Enhanced ShockBurst" auto-acknowledgement protocol doesn't work at 250Kbps speeds. There is no explicit mention of this in the datasheet, but there is a "hint" back in the appendix where they give examples of doing Enhanced ShockBurst transmissions vs. legacy (nRF24L01, non-plus) transmissions. They mention the data rate should be set to 1Mbps or 2Mbps for Enhanced ShockBurst. Who on earth writes these datasheets? Yargh! edit: Actually I take that back, it's even more confusing; in the section on Auto-Retransmit Delays, they provide delay timing minimums for 250Kbps (along with 1Mbps, 2Mbps). There is no point in setting the ARD register if you're not using auto-ack. yyrkoon 1 Quote Link to post Share on other sites
ike 53 Posted December 11, 2012 Share Posted December 11, 2012 Spirilis your lib is nice but is not very friendly. Yes, it's good if you want to send or receive something simple, but if you need to use it with UART or I2C and if you need to service interrupts from other pins ... things can get messy. But my primary concern is your lack of pair Rx and Tx examples. So I added such example, but it need beta testers, because it works for me but it may not work properly for you. Edit: I just realize that I post this in the wrong thread, so I moved it here. NRF24L01-MSP430G2553.rar Quote Link to post Share on other sites
spirilis 1,265 Posted January 7, 2013 Share Posted January 7, 2013 Library updated with F5xxx/6xxx USCI_A0/USCI_B0 support (minor differences; mainly the IRQ IE/IFG registers are different and the ISR layout is different) and confirmed working on an F5172. My nRF24L01+ BoosterPack needs a minor change; P2.2 (actually PJ.2 on the F5172 LP) isn't interrupt capable so the solder-jumper is cut and a jumper wire installed from the IRQ pad to the 3rd pad down from the top right (normally labeled XOUT or P2.7 on the value-line launchpad, but on the F5172 it's P1.6 and is interrupt-capable). Quote Link to post Share on other sites
Cw1X 2 Posted January 24, 2013 Share Posted January 24, 2013 Spirilis I could use your help. I'm stuck trying to connect G2452 with nrf24 modules. I made a new thread but bluehash suggested that I post a link here so here it is. http://forum.43oh.com/topic/3269-g2452-and-spirilis-nrf24l01-library/#entry28432 Thanks Quote Link to post Share on other sites
spirilis 1,265 Posted January 25, 2013 Share Posted January 25, 2013 Got it, I'll reply over there. Sent from my Android tablet using Tapatalk Quote Link to post Share on other sites
techazctu 0 Posted February 18, 2013 Share Posted February 18, 2013 nrf24L01 registers/commands and functions hi good job! Quote Link to post Share on other sites
gamersat678 1 Posted March 26, 2013 Share Posted March 26, 2013 Two things: The attached files main.c, and others point to nrf testdebug.txt (at least with firefox and chrome). Most likely will have to start a new thread but spirilis' code doesn't appear to work with msp430g2553's at least with ike's examples. (My hardware is fine, as since spirilis' code for the energia works perfectly) Have attempted to use both RF24_SPI_DRIVER_USCI_B and A (commenting each userconfig.h file accordingly). Swapped the necessary pins. Don't know what else could be wrong? Any help would be great. Note: Code stalls at if (rf_irq & RF24_IRQ_FLAGGED) { indefinitely for both tx and rx Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.