{"id":1527,"date":"2014-11-27T03:01:54","date_gmt":"2014-11-27T03:01:54","guid":{"rendered":"http:\/\/41j.com\/blog\/?p=1527"},"modified":"2014-11-28T15:51:33","modified_gmt":"2014-11-28T15:51:33","slug":"msp430-with-st7032i-now-working","status":"publish","type":"post","link":"https:\/\/41j.com\/blog\/2014\/11\/msp430-with-st7032i-now-working\/","title":{"rendered":"MSP430 with ST7032i, now working!"},"content":{"rendered":"<p><a href=\"http:\/\/41j.com\/blog\/wp-content\/uploads\/2014\/11\/ST7032i_msp430.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/41j.com\/blog\/wp-content\/uploads\/2014\/11\/ST7032i_msp430-1024x768.jpg\" alt=\"ST7032i_msp430\" width=\"700\" height=\"525\" class=\"aligncenter size-large wp-image-1528\" srcset=\"https:\/\/41j.com\/blog\/wp-content\/uploads\/2014\/11\/ST7032i_msp430-1024x768.jpg 1024w, https:\/\/41j.com\/blog\/wp-content\/uploads\/2014\/11\/ST7032i_msp430-300x225.jpg 300w, https:\/\/41j.com\/blog\/wp-content\/uploads\/2014\/11\/ST7032i_msp430.jpg 1632w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/a><\/p>\n<p>After much fiddling, I got the ST7032i working with an MSP430. The fundamental issue seemed to be getting the I2C data formatting correct. The MSP430 doesn&#8217;t have hardware I2C support. What it does have is something called the USI (Universal Serial Interface?). This gives some hardware support for serial transfers, but start\/stop\/ack bits need to be handled in software. The issue was that the I2C examples provided by TI describe 8bit transfers. With each transfer the address is sent, followed by an ACK, followed by 8bits of data. The USI can also be configured to send 16bits in one go. However the ST7032i doesn&#8217;t do either of those things. And it was only after looking at the output of a working Arduino example, and from reading the ST7032i datasheet that I actually understood what was happening.<\/p>\n<p>Basically the ST7032i expects I2C packets that looks like this:<\/p>\n<pre>\r\n[START][ADDRESS][ACK][DATA1][ACK][DATA2][ACK][STOP]\r\n<\/pre>\n<p>Such is my understanding a 3am anyway. And this format does appear to work. I&#8217;ve no idea if that&#8217;s normal for I2C 16bit comms, but certainly on the MSP430 you have to implement those ACKs in the middle of the data in software. For reference the board consumes ~0.5mA at 3.3V.<\/p>\n<p>Current source code is below, complete working example (with header) is available <a href=\"https:\/\/github.com\/new299\/msp430watch\/blob\/master\/i2clcd\/msp430x20x3_usi_07.c\">on github<\/a>. The code below should give some hint of how the process works however:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n#include &lt;msp430.h&gt;\r\n#include &quot;ST7032.h&quot;\r\n\r\nunsigned short MST_Data1 = 0x40;                     \/\/ Variable for transmitted data\r\nunsigned short MST_Data2 = 0x40;                     \/\/ Variable for transmitted data\r\nchar SLV_Addr = 0x7C;                  \/\/ Address is 0x48 &lt;&lt; 1 bit + 0 for Write\r\nint I2C_State = 0;                     \/\/ State variable\r\n\r\nint main(void)\r\n{\r\n  volatile unsigned int i;             \/\/ Use volatile to prevent removal\r\n\r\n  WDTCTL = WDTPW + WDTHOLD;            \/\/ Stop watchdog\r\n                __delay_cycles(250000);\r\n  if (CALBC1_1MHZ==0xFF)\t\t\t   \/\/ If calibration constants erased\r\n  {\t\t\t\t\t\t\t\t\t\t\t\r\n    while(1);                          \/\/ do not load, trap CPU!!\t\r\n  }\r\n  DCOCTL = 0;                               \/\/ Select lowest DCOx and MODx settings\r\n  BCSCTL1 = CALBC1_1MHZ;               \/\/ Set DCO\r\n  DCOCTL = CALDCO_1MHZ;\r\n\r\n\/\/  P1OUT = 0x0;\r\n\/\/  P1REN = 0x0;\r\n\r\n \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ P1SEL |= BIT6 + BIT7;\r\n  \/\/ enable all pull up\r\n  \/\/P1OUT = 0xFF;                        \/\/ P1.6 &amp; P1.7 Pullups, others to 0\r\n  \/\/P1REN = 0xFF;                       \/\/ P1.6 &amp; P1.7 Pullups\r\n  P1OUT = 0xC0;                        \/\/ P1.6 &amp; P1.7 Pullups, others to 0\r\n  P1REN |= 0xC0;                       \/\/ P1.6 &amp; P1.7 Pullups\r\n  P1DIR = 0xFF;                        \/\/ Unused pins as outputs\r\n  P2OUT = 0;\r\n  P2DIR = 0xFF;\r\n\r\n  USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; \/\/ Port &amp; USI mode setup\r\n  USICTL1 = USII2C+USIIE;              \/\/ Enable I2C mode &amp; USI interrupt\r\n  \/\/USICKCTL = USIDIV_3+USISSEL_2+USICKPL; \/\/ Setup USI clocks: SCL = SMCLK\/8 (~125kHz) \/\/ was USIDIV_3\r\n  USICKCTL = USIDIV_3+USISSEL_2+USICKPL; \/\/ Setup USI clocks: SCL = SMCLK\/8 (~125kHz) \/\/ was USIDIV_3\r\n  USICNT |= USIIFGCC;                  \/\/ Disable automatic clear control\r\n  USICTL0 &amp;= ~USISWRST;                \/\/ Enable USI\r\n  USICTL1 &amp;= ~USIIFG;                  \/\/ Clear pending flag\r\n  __enable_interrupt();\r\n\r\n  __delay_cycles(4000000);\r\n  int a=0;\r\n    int contrast = 0xff;\r\n  for(int n=1;;n++)\r\n  {\r\n    unsigned char _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;\r\n    _displayfunction |= LCD_2LINE;\r\n\r\n    if(n==1) MST_Data1 = 0x00;\r\n    if(n==1) MST_Data2 = LCD_FUNCTIONSET | _displayfunction;\r\n    if(n==2) MST_Data1 = 0x00;\r\n    if(n==2) MST_Data2 = LCD_FUNCTIONSET | _displayfunction | LCD_EX_INSTRUCTION;\r\n    if(n==3) MST_Data1 = 0x00;\r\n    if(n==3) MST_Data2 = LCD_EX_SETBIASOSC | LCD_BIAS_1_5 | LCD_OSC_183HZ;\r\n    if(n==4) MST_Data1 = 0x00;\r\n    if(n==4) MST_Data2 = LCD_EX_FOLLOWERCONTROL | LCD_FOLLOWER_ON | LCD_RAB_2_00;\r\n    if(n==5) MST_Data1 = 0x00;\r\n    if(n==5) MST_Data2 = LCD_FUNCTIONSET | _displayfunction;\r\n\r\n    \r\n    unsigned char _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;\r\n    if(n==6) MST_Data1 = 0x00;\r\n    if(n==6) MST_Data2 = LCD_DISPLAYCONTROL | _displaycontrol;\r\n\r\n    if(n==7) MST_Data1 = 0x00;\r\n    if(n==7) MST_Data2 = LCD_CLEARDISPLAY;\r\n\r\n    if(n==8) MST_Data1 = 0x00;\r\n    if(n==8) MST_Data2 = LCD_ENTRYMODESET |  LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;\r\n\r\n    if(n==9) MST_Data1 = 0x00;\r\n    if(n==9) MST_Data2 = LCD_FUNCTIONSET | _displayfunction | LCD_EX_INSTRUCTION;\r\n\r\n    uint8_t cont = 20;\r\n    if(n==10) MST_Data1 = 0x00;\r\n    if(n==10) MST_Data2 = LCD_EX_CONTRASTSETL | (cont &amp; 0x0f);\r\n    if(n==11) MST_Data1 = 0x00;\r\n    if(n==11) MST_Data2 = LCD_EX_POWICONCONTRASTH | LCD_ICON_ON | LCD_BOOST_ON | ((cont &gt;&gt; 4) &amp; 0x03);\r\n    if(n==12) MST_Data1 = 0x00;\r\n    if(n==12) MST_Data2 = LCD_FUNCTIONSET | _displayfunction;\r\n\r\n    if(n==13) MST_Data1 = (uint8_t) 0x40;\r\n    if(n==13) MST_Data2 = 'H';\r\n    if(n==14) MST_Data1 = (uint8_t) 0x40;\r\n    if(n==14) MST_Data2 = 'H';\r\n    if(n==15) MST_Data1 = (uint8_t) 0x40;\r\n    if(n==15) MST_Data2 = (uint8_t) 'H';\r\n    if(n==16) MST_Data1 = (uint8_t) 0x40;\r\n    if(n==16) MST_Data2 = 'H';\r\n\r\n    P1OUT |= 0x01;\r\n    __delay_cycles(500);\r\n    P1OUT &amp;= ~0x01;           \/\/ LED off\r\n    USICTL1 |= USIIFG;                 \/\/ Set flag and start communication\r\n    LPM0;                              \/\/ CPU off, await USI interrupt\r\n    \/\/ while (!(USICTL1 &amp; USIIFG));\/\/ busy wait\r\n    __delay_cycles(1000000);\r\n    if(n==4) {__delay_cycles(4000000); __delay_cycles(4000000);}\r\n    if(n==7) {__delay_cycles(4000000); __delay_cycles(4000000);}\r\n    if(n==32) {n=1;__delay_cycles(4000000); __delay_cycles(4000000); __delay_cycles(4000000);}\r\n  }\r\n}\r\n\r\n\/******************************************************\r\n\/\/ USI interrupt service routine\r\n******************************************************\/\r\n#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)\r\n#pragma vector = USI_VECTOR\r\n__interrupt void USI_TXRX (void)\r\n#elif defined(__GNUC__)\r\nvoid __attribute__ ((interrupt(USI_VECTOR))) USI_TXRX (void)\r\n#else\r\n#error Compiler not supported!\r\n#endif\r\n{\r\n                \/\/USICNT = USI16B | 16;\/\/(USICNT &amp; 0x0E) + 0x08;       \/\/ Bit counter = 8, start TX\r\n  switch(I2C_State)\r\n    {\r\n      case 0: \/\/ Generate Start Condition &amp; send address to slave\r\n              P1OUT &amp;= ~0x01;           \/\/ LED off\r\n              USISRL = 0x00;           \/\/ Generate Start Condition...\r\n              USICTL0 |= USIGE+USIOE;\r\n              USICTL0 &amp;= ~USIGE;\r\n              USISRL = SLV_Addr;       \/\/ ... and transmit address, R\/W = 0\r\n              USICNT = (USICNT &amp; 0xE0) + 0x08; \/\/ Bit counter = 8, TX Address\r\n              \/\/USICNT =  0xE0 + 0x08; \/\/ Bit counter = 8, TX Address\r\n              I2C_State = 2;           \/\/ Go to next state: receive address (N)Ack\r\n              break;\r\n\r\n      case 2: \/\/ Receive Address Ack\/Nack bit\r\n              USICTL0 &amp;= ~USIOE;       \/\/ SDA = input\r\n              USICNT |= 0x01;          \/\/ Bit counter = 1, receive (N)Ack bit\r\n              I2C_State = 4;           \/\/ Go to next state: check (N)Ack\r\n              break;\r\n\r\n      case 4: \/\/ Process Address Ack\/Nack &amp; handle data TX\r\n              USICTL0 |= USIOE;        \/\/ SDA = output\r\n              if (USISRL &amp; 0x01)       \/\/ If Nack received...\r\n              { \/\/ Send stop...\r\n                USISRL = 0x00;\r\n                USICNT |=  0x01;       \/\/ Bit counter = 1, SCL high, SDA low\r\n                I2C_State = 10;        \/\/ Go to next state: generate Stop\r\n              \/\/  P1OUT |= 0x01;         \/\/ Turn on LED: error\r\n                P1OUT |= 0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT &amp;= ~0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT |= 0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT &amp;= ~0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT |= 0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT &amp;= ~0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n              }\r\n              else\r\n              { \/\/ Ack received, TX data to slave...\r\n                USISRL = MST_Data1;     \/\/ Load data byte\r\n                USICNT = (USICNT &amp; 0x0E) + 0x08;       \/\/ Bit counter = 8, start TX\r\n                I2C_State = 41;         \/\/ Go to next state: receive data (N)Ack\r\n              }\r\n              break;\r\n      \r\n      case 41: \/\/ Receive Data Ack\/Nack bit\r\n              USICTL0 &amp;= ~USIOE;       \/\/ SDA = input\r\n              USICNT |= 0x01;          \/\/ Bit counter = 1, receive (N)Ack bit\r\n              I2C_State = 5;           \/\/ Go to next state: check (N)Ack\r\n              break;\r\n\r\n      case 5: \/\/ Process Address Ack\/Nack &amp; handle data TX\r\n              USICTL0 |= USIOE;        \/\/ SDA = output\r\n              if (USISRL &amp; 0x01)       \/\/ If Nack received...\r\n              { \/\/ Send stop...\r\n                USISRL = 0x00;\r\n                USICNT |=  0x01;       \/\/ Bit counter = 1, SCL high, SDA low\r\n                I2C_State = 10;        \/\/ Go to next state: generate Stop\r\n              \/\/  P1OUT |= 0x01;         \/\/ Turn on LED: error\r\n                P1OUT |= 0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT &amp;= ~0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT |= 0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT &amp;= ~0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT |= 0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT &amp;= ~0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT |= 0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT &amp;= ~0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n              }\r\n              else\r\n              { \/\/ Ack received, TX data to slave...\r\n                USISRL = MST_Data2;     \/\/ Load data byte\r\n                USICNT = (USICNT &amp; 0x0E) + 0x08;       \/\/ Bit counter = 8, start TX\r\n                I2C_State = 6;         \/\/ Go to next state: receive data (N)Ack\r\n              }\r\n              break;\r\n\r\n      case 6: \/\/ Receive Data Ack\/Nack bit\r\n              USICTL0 &amp;= ~USIOE;       \/\/ SDA = input\r\n              USICNT |= 0x01;          \/\/ Bit counter = 1, receive (N)Ack bit\r\n              I2C_State = 8;           \/\/ Go to next state: check (N)Ack\r\n              break;\r\n\r\n      case 8: \/\/ Process Data Ack\/Nack &amp; send Stop\r\n              USICTL0 |= USIOE;\r\n              if (USISRL &amp; 0x01)    {   \/\/ If Nack received...\r\n                P1OUT |= 0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT &amp;= ~0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT |= 0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT &amp;= ~0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT |= 0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT &amp;= ~0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT |= 0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT &amp;= ~0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT |= 0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT &amp;= ~0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT |= 0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n                P1OUT &amp;= ~0x01;         \/\/ Turn on LED: error\r\n                __delay_cycles(500000);\r\n              }\r\n              else                     \/\/ Ack received\r\n              {\r\n              \/\/  MST_Data++;            \/\/ Increment Master data\r\n              \/\/  P1OUT &amp;= ~0x01;        \/\/ Turn off LED\r\n              }\r\n              \/\/ Send stop...\r\n              USISRL = 0x00;\r\n              USICNT |=  0x01;         \/\/ Bit counter = 1, SCL high, SDA low\r\n              I2C_State = 10;          \/\/ Go to next state: generate Stop\r\n              break;\r\n\r\n      case 10:\/\/ Generate Stop Condition\r\n              USISRL = 0x0FF;          \/\/ USISRL = 1 to release SDA\r\n              USICTL0 |= USIGE;        \/\/ Transparent latch enabled\r\n              USICTL0 &amp;= ~(USIGE+USIOE);\/\/ Latch\/SDA output disabled\r\n              I2C_State = 0;           \/\/ Reset state machine for next transmission\r\n              LPM0_EXIT;               \/\/ Exit active for next transfer\r\n              break;\r\n    }\r\n\r\n  USICTL1 &amp;= ~USIIFG;                  \/\/ Clear pending flag\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>After much fiddling, I got the ST7032i working with an MSP430. The fundamental issue seemed to be getting the I2C data formatting correct. The MSP430 doesn&#8217;t have hardware I2C support. What it does have is something called the USI (Universal Serial Interface?). This gives some hardware support for serial transfers, but start\/stop\/ack bits need to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[1],"tags":[],"class_list":["post-1527","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1RRoU-oD","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts\/1527","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/comments?post=1527"}],"version-history":[{"count":5,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts\/1527\/revisions"}],"predecessor-version":[{"id":1537,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts\/1527\/revisions\/1537"}],"wp:attachment":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/media?parent=1527"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/categories?post=1527"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/tags?post=1527"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}