V0JT4 34 Posted February 5, 2012 Share Posted February 5, 2012 The goal of my project is to build ripple control receiver with some additional functions, main request was to receive massages and sent them via UART but current plan includes many more functions: - receive and decode messages - 4 relays triggered by certain message content - message logging to EEPROM with date and time from RTC - configuration will be stored on RTC DS1338 user memory - simple CLI via UART - 4 buttons and 20x4 character LCD interface - listing recorded messages with filtering Ripple control messages are transmitted to electricity distribution network, usually at 110kV or 22kV level and pass transformers down to end user 230V mains line. It is used to signal low and high tariff to electricity meters and high non-critical loads to optimize power distribution. The signal uses low modulation frequency, most common in Czech Republic is 216.7Hz. One message takes about 63 seconds to transmit. This allows one transmitter to cover large area. So far I'm getting around 200 messages a day with first receiver prototype. I plan to use these components: - MSP430G2553 - modified old receiver ZPA FMX-100 for signal extraction from mains, opto-coupled connection - AT24C512 I2C EEPROM, 64Kx8 bit - DS1338 I2C RTC - 20x4 character LCD HD44780 with shift register 74HCT164 - ULN2803 for relay switching with shift register 74HC595 - USB to UART module with FTDI or CP2102 chip, opto-coupled UART Does someone have good experience with DS1338 or would you recommend other RTC? I need 3.3V operation and battery backup, square wave output is welcomed. roadrunner84 and krzyk2 2 Quote Link to post Share on other sites
V0JT4 34 Posted February 18, 2012 Author Share Posted February 18, 2012 So far I have built two versions of simple message logger based on LaunchPad, first uses almost unmodified FMX-100 and the next one dropped top board and required some wire cutting on bottom board. I needed to use capacitor to smoothen the signal, 10uF with 2kOhm resistor to LED and opto coupler works just fine. So far I have around 100 hours recorded. Now it's time to concentrate on software part. Old receiver ZPA FMX-100: Inside: Message format, time is in secconds: Message recorded on scope: Logger V1: Logger V2: Receiver schema V0.8: Receiver board V0.8: Log sample, time is counted from system start just to get picture how often messages come: A1000B00000100P___0____________ +314:11 m:s A1000B01000000P_____1__________ +320:9 m:s A1001B10000000P___1____1_____1_ +324:12 m:s A1000B00110010P_______1_1___1__ +325:32 m:s A1000B00000100P_________0______ +326:52 m:s A0001B11000000P_______1_1___1__ +328:11 m:s A0010B10000000P______00________ +336:9 m:s A1010B11000100P00____00____0__0 +337:28 m:s A1000B00100000P____000_________ +338:47 m:s A1000B00001001P_0___010________ +340:8 m:s A1000B00010000P____0_______0__0 +341:27 m:s timotet, RobG, oPossum and 2 others 5 Quote Link to post Share on other sites
bluehash 1,581 Posted February 18, 2012 Share Posted February 18, 2012 Like the way you have documented your project. Ripple control messages are transmitted to electricity distribution network, usually at 110kV or 22kV level and pass transformers down to end user 230V mains line. It is used to signal low and high tariff to electricity meters and high non-critical loads to optimize power distribution. I never knew this existed. How are you going to use it? Quote Link to post Share on other sites
V0JT4 34 Posted February 19, 2012 Author Share Posted February 19, 2012 I have it assigned as a final project for my master degree. My tutor offered me couple projects and I picked this one. Before that I also didn't know this technology existed. It isn't used in my home city but it covers most of the Czech Republic. My tutor wishes to monitor the messages with simple in-device filtering and have few output relays programmable to certain addresses and behavior. It may also be used for some lab exercise like on Department of Electrical Power Engineering. Quote Link to post Share on other sites
V0JT4 34 Posted March 18, 2012 Author Share Posted March 18, 2012 I'm using I2C in my project with USCI. Here is code for write and read with repeated start, 8 or 16 bit EEPROM data address is possible. It was inspired by Anderson's code. May be useful for someone else. i2c.h #ifndef I2C_H_ #define I2C_H_ typedef unsigned char u8; typedef signed char s8; typedef unsigned int u16; typedef signed int s16; typedef struct { u8 count; u8 state; u16 address; u8 *buffer; } i2c_data_t; #define size_tr(size, addr16) ((size-1)<<1)|(addr16 & 0x01) // number of bytes to transfer(1 to 128, 2+ for RX), device ID, buffer pointer, is 16bit addressing, memory address #define i2c_tx(size, id, buffer, addr16, address) i2c_trans(size_tr(size,addr16), id, buffer, address) #define i2c_rx(size, id, buffer, addr16, address) i2c_trans(size_tr(size,addr16), id|0x01, buffer, address) // number of bytes to transfer|16 bit addressing, device ID|dirrection, buffer pointer, memory address void i2c_trans(u8 size, u8 id, u8 buffer[], u16 address); void i2c_init(void); // setup u8 i2c_int(void); // data transfer interrupt u8 i2c_eint(void); // NACK interrupt #endif /*I2C_H_*/ i2c.c #include "msp430g2553.h" #include "i2c.h" // i2c states #define WRITE 0x00 #define READ 0x01 #define ADDR16 0x02 #define ADDRTR 0x04 #define REPSTT 0x08 i2c_data_t i2c_data = {0, 0, 0, 0}; void i2c_init(void) { P1SEL |= BIT6 + BIT7; //Set I2C pins P1SEL2 |= BIT6 + BIT7; UCB0CTL1 |= UCSWRST; //Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; //I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; //Use SMCLK, keep SW reset UCB0BR0 = 12; //fSCL = SMCLK/12 = ~100kHz UCB0BR1 = 0; UCB0CTL1 &= ~UCSWRST; //Clear SW reset, resume operation IE2 |= UCB0TXIE | UCB0RXIE; //Enable TX, RX interrupt UCB0I2CIE = UCNACKIE; // NACK interrups } void i2c_trans(u8 size, u8 id, u8 *buffer, u16 address) { i2c_data.state = (id & READ) | ADDRTR; // byte counter if (size & 0x01) i2c_data.state |= ADDR16; i2c_data.count = (size >> 1) + 1; // byte counter i2c_data.address = address; // byte counter i2c_data.buffer = buffer; // byte counter UCB0I2CSA = id >> 1; // Slave Address 01101000 0x68 RTC //Slave Address 01010000 0x50 EEPROM UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition __bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts // Remain in LPM0 until all data is transferred } u8 i2c_int(void) { if (i2c_data.state == WRITE) { if (i2c_data.count > 0) { //Check TX byte counter UCB0TXBUF = *i2c_data.buffer++; // Load TX buffer i2c_data.count--; //Decrement TX byte counter } else if (i2c_data.count == 0) { //last byte transferred UCB0CTL1 |= UCTXSTP; //I2C stop condition while (UCB0CTL1 & UCTXSTP); //Ensure stop condition got sent IFG2 &= ~UCB0TXIFG; //Clear USCI_B0 TX int flag return 1; //Exit LPM0 } } else if (i2c_data.state == READ) { *i2c_data.buffer++ = UCB0RXBUF; i2c_data.count--; //Decrement RX byte counter if (i2c_data.count == 1) { //Check RX byte counter, 1 byte remaining UCB0CTL1 |= UCTXSTP; // I2C stop condition } if (i2c_data.count == 0) { //Check RX byte counter, last byte received while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent return 1; // Exit LPM0 } } else if (i2c_data.state & ADDR16) { // high byte address transmit UCB0TXBUF = _swap_bytes(i2c_data.address); i2c_data.state &= ~ADDR16; } else if (i2c_data.state & ADDRTR) { // low byte address transmit UCB0TXBUF = i2c_data.address; i2c_data.state &= ~ADDRTR; if (i2c_data.state) { // repeated Start for RX i2c_data.state |= REPSTT; } } else if (i2c_data.state & REPSTT) { // repeated start required i2c_data.state &= ~REPSTT; UCB0CTL1 &= ~UCTR; // I2C RX UCB0CTL1 |= UCTXSTT; // I2C repeated Start condition for RX IFG2 &= ~UCB0TXIFG; //Clear USCI_B0 TX int flag } return 0; } u8 i2c_eint(void) { if (UCB0STAT & UCNACKIFG) { // send STOP if slave sends NACK UCB0CTL1 |= UCTXSTP; UCB0STAT &= ~UCNACKIFG; return 1; } return 0; } example main.c #include "msp430g2553.h" #include "i2c.h" u8 txdata[] = {'H', 'E', 'L', 'L', 'O', ' ', 'W', 'O', 'R', 'L', 'D'}; u8 rxdata[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; void main(void) { WDTCTL = WDTPW + WDTHOLD; //Stop WDT BCSCTL1 = CALBC1_1MHZ; //Set DCO to 1MHz DCOCTL = CALDCO_1MHZ; // UART setup P1SEL = BIT1 + BIT2; //Set RXD and TXD P1SEL2 = BIT1 + BIT2; UCA0CTL1 |= UCSSEL_2 | UCSWRST; //Have USCI use SMCLK AKA 1MHz main CLK UCA0BR0 = 104; //Baud = 9600 UCA0BR1 = 0; UCA0MCTL = UCBRS_1; //Modulation UCA0CTL1 &= ~UCSWRST; //Start USCI i2c_init(); // init I2C __delay_cycles(20000); //Just a start up delay i2c_rx(11, 0xA0, rxdata, 0, 0); //i2c RX data u8 i = 0; while (i < 11) { while (!(IFG2 & UCA0TXIFG)); UCA0TXBUF = rxdata[i]; //UART TX data i++; } i2c_tx(11, 0xA0, txdata, 0, 0); //i2c TX 11 bytes("HELLO WORLD") __delay_cycles(20000); //Allow EEPROM to write data i2c_rx(11, 0xA0, rxdata, 0, 0); //i2c RX data i = 0; while (i < 11) { while (!(IFG2 & UCA0TXIFG)); UCA0TXBUF = rxdata[i]; //UART TX data i++; } __bis_SR_register(CPUOFF + GIE); //Wait for a reset } // I2C data transfer vector #pragma vector = USCIAB0TX_VECTOR __interrupt void USCIAB0TX_ISR(void) { if (i2c_int()) __bic_SR_register_on_exit(CPUOFF); //Exit LPM0; } // I2C status vector #pragma vector = USCIAB0RX_VECTOR __interrupt void USCIAB0RX_ISR(void) { if (i2c_eint()) { while (!(IFG2 & UCA0TXIFG)); // send error via UART UCA0TXBUF = '#'; } } waic, turd, oPossum and 2 others 5 Quote Link to post Share on other sites
V0JT4 34 Posted April 29, 2012 Author Share Posted April 29, 2012 This week I got PCBs from my tutor and had time to populate and do some test. Boards were produced by local company so the price was quite high. I'm glad there are also services like Seed. gordon, RobG, bluehash and 1 other 4 Quote Link to post Share on other sites
majeddotcom 0 Posted August 13, 2012 Share Posted August 13, 2012 Hi; Thank you so much for sharing. I`m going to use i2c interface with an EEprom memory chip from microchip (24lc256). I used your code (I`m using CCS) for communication. but when I debug the program it will stuck before ( u8 i2c_int(void) { ) in i2c.c file and doesn`t do any thing after that. first time it goes to that and after going back to interrupt and coming back to i2c.c it stuck at this point. what is the problem? Quote Link to post Share on other sites
V0JT4 34 Posted August 14, 2012 Author Share Posted August 14, 2012 Have you just downloaded and compiled the example code or have you done any modification? The interrupt service routine must contain the if clause to correctly wake up processor after I2C transaction is done or you have to use different approach not to overlap 2 transactions. Quote Link to post Share on other sites
majeddotcom 0 Posted August 14, 2012 Share Posted August 14, 2012 Thanks man for response, I used exactly your code . without any change. even I removed any other things and just tried to send and receive a sample data. you know, when it wants to start communication it seems it`s hanging. why hanging? I can`t understand. I`m sure it`s not IC problem . I removed P1.6 jumper and the same GND for both IC and 10K resistor pullup for SDA pin. when I`m in debug mode and check the program line by line, when it comes back from interrupt routing and wants to start reading for the first time, it hangs. any idea? Quote Link to post Share on other sites
V0JT4 34 Posted August 14, 2012 Author Share Posted August 14, 2012 First thing that pops my mind is to set 16bit addressing bit because your EEPROM chip uses it. replace i2c_rx(11, 0xA0, rxdata, 0, 0); with i2c_rx(11, 0xA0, rxdata, 1, 0); In test example I was using small EEPROM that uses only 8bit addressing, STMicro 24C16. I think all devices up to 256B and some up to 2KB (from outside they behave like 8 I2C devices in one pack) use it. In final design I used 64KB chip that requires 16bit addressing. You may also check if WP, A0, A1 and A2 are connected to GND. Another option is to place break point into I2C status interrupt that is hit when slave sends NACK or does not respond at all. Best way is to have scope or logic analyzer to see the waveform. You can watch transaction progress if you place break point at the beginning of "u8 i2c_int(void)" in i2c.c. majeddotcom 1 Quote Link to post Share on other sites
majeddotcom 0 Posted August 14, 2012 Share Posted August 14, 2012 nothing yet. I removed interrupts and used while loop for sending data . now it`s working. but there is another problem. now it goes to i2c_int() . also it goes to write routine or read routine correctly. but after i2c_data.count==0 it will stay in : while (UCB0CTL1 & UCTXSTP); and can not pass this step. I don`t have osiloscope around here now. do you think this problem is because of no response from EEprom memory? I changed the code like this: i2c_tx(11, 0xA0, txdata, 1, 0); //i2c TX 11 bytes("HELLO WORLD") while (!(i2c_int())){ } and also I removed __bis_SR_register(CPUOFF + GIE); from i2c.c Quote Link to post Share on other sites
V0JT4 34 Posted August 15, 2012 Author Share Posted August 15, 2012 I'm not sure how functional it may be without interrupts as its written to depend on them and as is described in MSP430 2xxx User's Guide. You would need to check some ready/busy flags of USCI_B module. However if you get to tx function you can verify functionality: Run upto tx count=0 Reset Run to rx count=0 and examine the memory in debug mode rxdata buffer should contain same data as txdata You can also test Anderson's code for I2C USCI, it is for 16bit addressing. majeddotcom 1 Quote Link to post Share on other sites
LastMile 0 Posted April 15, 2013 Share Posted April 15, 2013 Hi, Could you please share a bit more info on your Logger V2? Especially, I Quote Link to post Share on other sites
V0JT4 34 Posted April 15, 2013 Author Share Posted April 15, 2013 I have all the data stored at http://sunny.ok.cvut.cz/~vojta/hdo/cd/ src-test contains the code for Logger. If you want to use it with unmodified FMX-100, you need a diode from 5.6V pin to LaunchPad USB Vcc and one NPN transistor for level shifting from HDO data pin to P1.3. And don't forget to connect ground. Simply connection would be as on picture for LoggerV1. It may be better to add RC filter on transistor input to suppress glitches. Or you can use optocoupler level shifting schema shown in 2nd post. Quote Link to post Share on other sites
LastMile 0 Posted April 17, 2013 Share Posted April 17, 2013 Thank you for the link. Lots of valuable data! 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.