Jump to content

pillum

Members
  • Content Count

    37
  • Joined

  • Last visited


Reputation Activity

  1. Like
    pillum reacted to oPossum in Measuring time in clocks between edges   
    Here is tested code that uses a single G2553. Connect a jumper wire from P1.6 (timer A0 output) to P2.1 (timer A1 capture input)
     
    The output is 400 cycles on and then 600 cycles off.
    The ca[] array will have alternating values of 400 and 600. (run, halt, watch)
     

    #include void main() { WDTCTL = WDTPW | WDTHOLD; BCSCTL1 = CALBC1_16MHZ; DCOCTL = CALDCO_16MHZ; P1DIR = BIT6; P1SEL = BIT6; P2DIR = 0; P2SEL = BIT1; TA0CCR0 = 1000 - 1; TA0CCR1 = 400; TA0CTL = TASSEL_2 | MC_1; TA0CCTL1 = OUTMOD_6; TA1CTL = TASSEL_2 | MC_2; TA1CCTL1 = CM_3 | SCS | CCIS_0 | CAP | CCIE; _enable_interrupts(); for(;; } unsigned cn = 0; // Timer capture number unsigned ca[16]; // Timer capture array #pragma vector=TIMER1_A1_VECTOR __interrupt void TimerA1(void) { static unsigned tl; // Last timer capture volatile unsigned n = TA1IV; // Read interrupt vector to reset interrupt flag const unsigned tc = TA1CCR1; // Current timer capture const unsigned te = tc - tl; // Elapsed time tl = tc; // Update last timer capture ca[cn++ & 15] = te; // Save captured time in array }
  2. Like
    pillum reacted to RobG in Ethernet Booster Pack   
    All boards assembled!
    Will test them tonight and ship on Monday.
     

  3. Like
    pillum reacted to RobG in TLC5940 examples   
    TLC5940 code examples.

    1. UART to TLC

    2. Chasing light, useful for your next Knight Rider project
    #include #define SCLK_PIN BIT5 #define MOSI_PIN BIT7 #define GSCLK_PIN BIT4 #define BLANK_PIN BIT0 #define XLAT_PIN BIT2 typedef unsigned char u_char; u_char leds[16] = { 0, }; void updateTLC(); void main(void) {     WDTCTL = WDTPW + WDTHOLD; // disable WDT     BCSCTL1 = CALBC1_16MHZ; // 16MHz clock     DCOCTL = CALDCO_16MHZ;     P1OUT &= ~(BLANK_PIN + XLAT_PIN);     P1DIR |= BLANK_PIN + XLAT_PIN;     P1DIR |= GSCLK_PIN; // port 1.4 configured as SMCLK out     P1SEL |= GSCLK_PIN;     // setup timer     CCR0 = 0xFFF;     TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, up mode, 1:1     CCTL0 = CCIE; // CCR0 interrupt enabled     // setup UCB0     P1SEL |= SCLK_PIN + MOSI_PIN;     P1SEL2 |= SCLK_PIN + MOSI_PIN;     UCB0CTL0 = UCCKPH + UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master     UCB0CTL1 |= UCSSEL_2; // SMCLK     UCB0BR0 |= 0x01; // 1:1     UCB0BR1 = 0;     UCB0CTL1 &= ~UCSWRST; // clear SW     updateTLC();     P1OUT |= XLAT_PIN;     P1OUT &= ~XLAT_PIN;     _bis_SR_register(GIE);     leds[0] = 0x0F;     u_char counter = 0;     u_char direction = 0;     while (1) {         _delay_cycles(500000);         if (direction) {             counter--;             leds[counter] = 0x0F;             leds[counter + 1] = 0;             if (counter == 0)                 direction = 0;         } else {             counter++;             leds[counter] = 0x0F;             leds[counter - 1] = 0;             if (counter == 15)                 direction = 1;         }     } } void updateTLC() {     u_char ledCounter = 8;     while (ledCounter-- > 0) {         UCB0TXBUF = leds[(ledCounter << 1) + 1] << 4;         while (!(IFG2 & UCB0TXIFG))             ; // TX buffer ready?         UCB0TXBUF = leds[ledCounter << 1];         while (!(IFG2 & UCB0TXIFG))             ; // TX buffer ready?         UCB0TXBUF = 0;         while (!(IFG2 & UCB0TXIFG))             ; // TX buffer ready?     } } #pragma vector = TIMER0_A0_VECTOR __interrupt void Timer_A0(void) {     P1OUT |= BLANK_PIN;     P1OUT |= XLAT_PIN;     P1OUT &= ~XLAT_PIN;     P1OUT &= ~BLANK_PIN;     updateTLC(); }
  4. Like
    pillum reacted to RobG in Controlling TLC5940 with MSP430G2553 doesn't work   
    Brightness data for all LEDs is stored in leds[]. In this example, I am only using 4 bits for 16 levels of brightness.
    Sending one byte via UART updates data in leds[] for only one LED.
    updateTLC() updates all LEDs, sends 192 bits.
     
    TLC's GS register is 12 bits, UCB0 can only send 8 bits at a time. In my code, I am sending GS data for 2 LEDs in each iteration, 24 bits, 3 bytes. Total of 8 iterations.
    So for example, LED 15 and 14 is at max, 0x0F in leds[]. 00001111 and 00001111
    First byte, I am taking leds[15] and shifting it 4 times to the left (basically multiplying it by 16 to get 12 bit value.) 11110000
    Next byte contains 4 lower bits of LED 15 and 4 upper bits of LED 14. Since we have only 16 levels, 4 lower bits are always 0, so we send only leds[14] (we don't have to shift it because they are in the right position. 00001111
    Last byte, all 0s since we have 16 levels only. In the end, we send: 111100000000 111100000000. Repeat that 7 more times for the remaining 14 LEDs
     
    If you want to have more levels, for example 256, all you need to do is change updateTLC()
     

    UCB0TXBUF = leds[(ledCounter << 1) + 1] ; while (!(IFG2 & UCB0TXIFG)) ; // TX buffer ready? UCB0TXBUF = leds[ledCounter << 1] >> 4; while (!(IFG2 & UCB0TXIFG)) ; // TX buffer ready? UCB0TXBUF = leds[ledCounter << 1] << 4; while (!(IFG2 & UCB0TXIFG)) ; // TX buffer ready?
  5. Like
    pillum reacted to RobG in Controlling TLC5940 with MSP430G2553 doesn't work   
    MSP430 SMCLK out -> TLC GSCLK
    MSP430 UCB0 SCLK -> TLC SCLK
     
     
    GSCLK and BLANK are used for PWM. GSCLK clocks the PWM counter, BLANK turns LEDs off and sets PWM counter to 0.
    When PWM counter reaches 0xFFF, it stops. If you do not pulse BLANK at that time, LEDs will remain off. Pulsing BLANK will restart PWM count.
    Instead of pulsing GSCLK and keeping track in code, you use timer module.
    4096 pulses would require 20k+ clock cycles per PWM cycle!
    This way, you need only ~20 of them (per PWM cycle.)
     
    XLAT is used for latching data. Since new data replaces old one when XLAT goes high, latching should happen when PWM counter is inactive (BLANK is 1.)
    You could move updateTLC() and XLAT to timer's ISR, but I think the effect of latching in the middle of PWM cycle is not significant. Doing it that way means new data will be sent to TLC every PWM cycle, where my original code sends data only when something changes.
     
    Something like this:
     
    #include  
    #define RX_PIN
  6. Like
    pillum reacted to RobG in Controlling TLC5940 with MSP430G2553 doesn't work   
    Here is the implementation of what I was suggesting.
    Send byte through UART to light up the LED.
    Upper nibble controls LED #, lower nibble brightness (0-15)
    So, to set LED#1 to max, you send 0x1F, LED#16 to 50%, send 0xF7
    LED#4 '0' = 0%, '7' = 50%, '?' = 100%
    LED#5 '@ = 0%, 'G' = 50%, 'O' = 100%
    LED#6 'P' = 0%, 'W' = 50%, '_' = 100%
    and so on.
     
    BTW, DCPRG and VPRG are grounded.
     

    #include #define RX_PIN BIT1 #define SCLK_PIN BIT5 #define MOSI_PIN BIT7 #define GSCLK_PIN BIT4 #define BLANK_PIN BIT0 #define XLAT_PIN BIT2 typedef unsigned char u_char; u_char leds[16] = { 0, }; void updateTLC(); void main(void) { WDTCTL = WDTPW + WDTHOLD; // disable WDT BCSCTL1 = CALBC1_16MHZ; // 16MHz clock DCOCTL = CALDCO_16MHZ; P1OUT &= ~(BLANK_PIN + XLAT_PIN); P1DIR |= BLANK_PIN + XLAT_PIN; P1DIR |= GSCLK_PIN; // port 1.4 configured as SMCLK out P1SEL |= GSCLK_PIN; // setup timer CCR0 = 0xFFF; TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, up mode, 1:1 CCTL0 = CCIE; // CCR0 interrupt enabled // setup UCA0 P1SEL |= RX_PIN; P1SEL2 |= RX_PIN; UCA0CTL1 |= UCSSEL_2; UCA0BR0 = 0x82; // 9600@16MHz UCA0BR1 = 0x06; UCA0MCTL = UCBRS_6; UCA0CTL1 &= ~UCSWRST; IE2 |= UCA0RXIE; // setup UCB0 P1SEL |= SCLK_PIN + MOSI_PIN; P1SEL2 |= SCLK_PIN + MOSI_PIN; UCB0CTL0 = UCCKPH + UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master UCB0CTL1 |= UCSSEL_2; // SMCLK UCB0BR0 |= 0x01; // 1:1 UCB0BR1 = 0; UCB0CTL1 &= ~UCSWRST; // clear SW updateTLC(); _bis_SR_register(GIE); } void updateTLC() { u_char ledCounter = 8; while (ledCounter-- > 0) { UCB0TXBUF = leds[(ledCounter << 1) + 1] << 4 ; while (!(IFG2 & UCB0TXIFG)) ; // TX buffer ready? UCB0TXBUF = leds[ledCounter << 1]; while (!(IFG2 & UCB0TXIFG)) ; // TX buffer ready? UCB0TXBUF = 0; while (!(IFG2 & UCB0TXIFG)) ; // TX buffer ready? } P1OUT |= XLAT_PIN; P1OUT &= ~XLAT_PIN; } #pragma vector=USCIAB0RX_VECTOR __interrupt void USCI0RX_ISR(void) { u_char byte = UCA0RXBUF; // copy RX buffer u_char led = byte >> 4; // upper 4 bits are LED # leds[led] = byte & 0x0F; // lower 4 bits are brightness 0-15 // update TLC updateTLC(); } #pragma vector = TIMER0_A0_VECTOR __interrupt void Timer_A0(void) { P1OUT |= BLANK_PIN; P1OUT &= ~BLANK_PIN; }
  7. Like
    pillum reacted to RobG in Controlling TLC5940 with MSP430G2553 doesn't work   
    No, GSCLK and SCLK are two independent clock signals and do not have to be synchronized.
    Use P1.4 (SCLK out) for GSCLK, set timer to upmode, 1:1 SMCLK, and CCR to 0xFFF.
    In timer's ISR, pulse BLANK, P1.3 for example.
    P1.0 -> XLAT
    P1.5 (USCI SCLK) -> SCLK
    P1.7 (SIMO) -> SIN
    P1.6 (SOMI) -> SOUT (optional)
    P1.1 UART RX
    P2.0 -> VPRG (optional)
    P2.1 -> DCPRG (optional)
     
    Use UCA0 in UART mode to receive data from PC, UCB0 in SPI mode to send data to TLC.
  8. Like
    pillum reacted to RobG in Controlling TLC5940 with MSP430G2553 doesn't work   
    Sounds like a wire connection issue.
    You may want to use 3 male headers with soldered wires, that will eliminate flaky jumper wires.
    I do that all the time, saved me some headaches
     

  9. Like
    pillum reacted to RobG in Controlling TLC5940 with MSP430G2553 doesn't work   
    Same results as Kyle.
    Added remaining LEDs later on just to make sure LP's LDO is not an issue here and all LEDs light up. My RIREF is 2k2, so the total current is just under 320mA.
     

  10. Like
    pillum reacted to kylej1050 in Controlling TLC5940 with MSP430G2553 doesn't work   
    I did this with the 2553 installed in a launchpad with 5940 in breadboard.
     
    Do you get them to light at all? I have the 5940 with all leds burning bright right now using your code. I edited the code and it does change the way the leds behave. Your GSCLK is very slow however as the leds that don't have full brightness blink instead of dimming. If you add "BCSCTL1 = CALBC1_16MHZ;" under your watchdog code it will dim though.
     
    Your code keeps the processor very busy. I would recommend using a timer to output your clock signal while the MSP goes about other business. Doesn't matter if you pre-program a routine but if you want the MSP to do anything else while running this chip there is no time for it.
     
    Do you have bypass capacitors on the breadboard?
  11. Like
    pillum reacted to oPossum in Tiny printf() - C version   
    This is a tiny printf() function that can be used with the chips that come with the Launchpad. Code size is about 640 bytes with CCS.
     
    There are 7 format specifiers:
    %c - Character
    %s - String
    %i - signed Integer (16 bit)
    %u - Unsigned integer (16 bit)
    %l - signed Long (32 bit)
    %n - uNsigned loNg (32 bit)
    %x - heXadecimal (16 bit)
     
    Field width, floating point and other standard printf() features are not supported.
     
    printf() code

    #include "msp430g2231.h" #include "stdarg.h" void putc(unsigned); void puts(char *); static const unsigned long dv[] = { // 4294967296 // 32 bit unsigned max 1000000000, // +0 100000000, // +1 10000000, // +2 1000000, // +3 100000, // +4 // 65535 // 16 bit unsigned max 10000, // +5 1000, // +6 100, // +7 10, // +8 1, // +9 }; static void xtoa(unsigned long x, const unsigned long *dp) { char c; unsigned long d; if(x) { while(x < *dp) ++dp; do { d = *dp++; c = '0'; while(x >= d) ++c, x -= d; putc(c); } while(!(d & 1)); } else putc('0'); } static void puth(unsigned n) { static const char hex[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; putc(hex[n & 15]); } void printf(char *format, ...) { char c; int i; long n; va_list a; va_start(a, format); while(c = *format++) { if(c == '%') { switch(c = *format++) { case 's': // String puts(va_arg(a, char*)); break; case 'c': // Char putc(va_arg(a, char)); break; case 'i': // 16 bit Integer case 'u': // 16 bit Unsigned i = va_arg(a, int); if(c == 'i' && i < 0) i = -i, putc('-'); xtoa((unsigned)i, dv + 5); break; case 'l': // 32 bit Long case 'n': // 32 bit uNsigned loNg n = va_arg(a, long); if(c == 'l' && n < 0) n = -n, putc('-'); xtoa((unsigned long)n, dv); break; case 'x': // 16 bit heXadecimal i = va_arg(a, int); puth(i >> 12); puth(i >> 8); puth(i >> 4); puth(i); break; case 0: return; default: goto bad_fmt; } } else bad_fmt: putc(c); } va_end(a); }
     
    test code

    #include "msp430g2231.h" void serial_setup(unsigned out_mask, unsigned in_mask, unsigned duration); void printf(char *, ...); void main(void) { char *s; char c; int i; unsigned u; long int l; long unsigned n; unsigned x; // Disable watchdog WDTCTL = WDTPW + WDTHOLD; // Use 1 MHz DCO factory calibration DCOCTL = 0; BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; // Setup the serial port // Serial out: P1.1 (BIT1) // Serial in: P1.2 (BIT2) // Bit rate: 9600 (CPU freq / bit rate) serial_setup(BIT1, BIT2, 1000000 / 9600); printf("%s", "\r\n*** printf() test ***\r\n"); s = "test"; c = 'X'; i = -12345; u = 12345; l = -1234567890; n = 1234567890; x = 0xABCD; printf("String %s\r\n", s); printf("Char %c\r\n", c); printf("Integer %i\r\n", i); printf("Unsigned %u\r\n", u); printf("Long %l\r\n", l); printf("uNsigned loNg %n\r\n", n); printf("heX %x\r\n", x); printf("multiple args %s %c %i %u %l %n %x\r\n", s, c, i, u, l, n, x); printf("\r\n*** Done ***\r\n"); for(;; }

  12. Like
    pillum reacted to SirZusa in TLC5940 - "Full Implementation"   
    hi there, as i already said in another thread i was working on the code for controlling the TLC5940. here it is!
     
    100% working. specification-sheet i used to code this: http://www.ti.com/lit/sw/slvc106/slvc106.pdf
     


    [*:1o0bnvvd]supports DC
    [*:1o0bnvvd]supports Grayscale
    [*:1o0bnvvd]recommendet implementation from the Programming Flow Chart
    [*:1o0bnvvd]does not support EEPROM-programming (cause you will need 22 Volts for this)
    [*:1o0bnvvd]actually does not support "Use DC from EEPROM-mode"
    [*:1o0bnvvd]LOD-Check not implemented for now ... but i think i will do this soon if i find more literature on this
     

    /*** TLC5940 ***/ #include "msp430g2553.h" #include "stdbool.h" // How many TLC's daisy-chained #define n 2 /*** Ports ***/ // STATUS-LED #define PORT_STATUS_LED P1OUT #define PIN_STATUS_LED BIT0 // BLANK - to pin 23 of every TLC5940 #define PORT_BLANK P1OUT #define PIN_BLANK BIT3 // XLAT - to pin 24 of every TLC5940 #define PORT_XLAT P1OUT #define PIN_XLAT BIT4 // SCLK - to pin 25 of every TLC5940 #define PORT_SCLK P1OUT #define PIN_SCLK BIT5 // SIN - to pin 26 of first TLC5940 #define PORT_SIN P1OUT #define PIN_SIN BIT6 // GSCLK - to pin 18 of every TLC5940 #define PORT_GSCLK P1OUT #define PIN_GSCLK BIT7 // DCPRG - to pin 19 of every TLC5940 #define PORT_DCPRG P2OUT #define PIN_DCPRG BIT3 // VPRG - to pin 27 of every TLC5940 #define PORT_VPRG P2OUT #define PIN_VPRG BIT4 /*** DO NOT EDIT BELOW ***/ #define x (n * 16) /*** Brightness-Correction ***/ const int pwm_table[256] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,26,28,30,32,34,36,38,40,42, 44,46,48,50,52,55,58,61,64,67,70,73,76,79,82,85,88,91,94,97,100,103,106,110,114,118,122,126,130, 134,138,142,146,150,154,158,162,166,170,174,178,182,186,190,195,200,205,210,215,220,225,230,235, 240,245,250,255,260,265,270,275,280,285,290,297,304,311,318,325,332,339,346,353,360,367,374,381, 388,395,402,409,416,423,430,437,444,451,458,467,476,485,494,503,512,521,530,539,548,557,566,575, 584,593,602,611,626,641,656,671,686,701,716,731,746,761,776,791,806,821,836,851,866,881,896,916, 936,956,976,996,1016,1036,1056,1076,1096,1116,1136,1156,1176,1196,1221,1246,1271,1296,1321,1346, 1371,1396,1421,1446,1471,1496,1526,1556,1586,1616,1646,1676,1706,1736,1766,1796,1826,1856,1886, 1921,1956,1991,2026,2061,2096,2131,2166,2201,2236,2271,2306,2341,2376,2411,2446,2481,2516,2551, 2586,2621,2656,2691,2726,2761,2796,2832,2868,2904,2940,2976,3012,3048,3084,3120,3156,3192,3228, 3266,3304,3342,3380,3418,3456,3494,3532,3572,3612,3652,3692,3737,3782,3827,3872,3917,3962,4007,4095 }; // holds the actual DC-data for each channel char dc_data[x] = {63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63}; /*** Variables ***/ // first PWM-cycle after Dot Correction Data has changed? bool FirstCycleFlag; // holds the actual PWM-data for each channel int gs_data[x]; /*** small userdefined Functions ***/ // useful macros #define setLow(port, pin) { port &= ~pin; } #define setHigh(port, pin) { port |= pin; } #define pulse(port, pin) { setHigh(port, pin); setLow(port, pin); } #define toggle(port, pin) { port ^= pin; } /*** transfer DC-data to our TLC5940's ***/ void send_DC() { // DCPRG - dont use DC-EEPROM setHigh(PORT_DCPRG, PIN_DCPRG); // VPRG - set Dot Correction Input setHigh(PORT_VPRG, PIN_VPRG); // Reset Counter int Counter = 0; // clock in Dot Correction Data for (; { // Counter > n * 96 - 1 // 6 Bits * 16 Channels = 96 if (Counter > (n * 96 - 1)) { pulse(PORT_XLAT, PIN_XLAT); break; } else { // Set SIN to DC Data[Counter] // MSB first if ((dc_data[Counter / 6] >> (5 - (Counter % 6))) & 0x01) { setHigh(PORT_SIN, PIN_SIN); } else { setLow(PORT_SIN, PIN_SIN); } pulse(PORT_SCLK, PIN_SCLK); Counter++; } } // dont save to EEPROM - so we finish here // set FirstCycleFlag to true FirstCycleFlag = true; } /*** transfer PWM-data to our TLC5940's ***/ void send_GS() { if (FirstCycleFlag == true) { setLow(PORT_VPRG, PIN_VPRG); } // Reset Counters int GSCLK_Counter = 0; int Data_Counter = 0; setLow(PORT_BLANK, PIN_BLANK); // clock in PWM Data for (; { if (GSCLK_Counter > 4095) { setHigh(PORT_BLANK, PIN_BLANK); pulse(PORT_XLAT, PIN_XLAT); if (FirstCycleFlag == true) { pulse(PORT_SCLK, PIN_SCLK); } FirstCycleFlag = false; break; } else { // 12 Bit * 16 Channels = 192 if (Data_Counter > (n * 192 - 1)) { pulse(PORT_GSCLK, PIN_GSCLK); GSCLK_Counter++; } else { // Set SIN to GS Data[Counter] // MSB first if ((gs_data[Data_Counter / 12] >> (11 - (Data_Counter % 12))) & 0x01) { setHigh(PORT_SIN, PIN_SIN); } else { setLow(PORT_SIN, PIN_SIN); } pulse(PORT_SCLK, PIN_SCLK); Data_Counter++; pulse(PORT_GSCLK, PIN_GSCLK); GSCLK_Counter++; } } } } /*** Our main program ***/ void main(void) { // stop WDT - WDTPW is the password needed for every write and then tell watchdog to hold WDTCTL = WDTPW | WDTHOLD; BCSCTL1 = CALBC1_16MHZ; DCOCTL = CALDCO_16MHZ; // initialize the ports connected to the TLC's // set ports to output-direction P1DIR |= (PIN_STATUS_LED|PIN_BLANK|PIN_XLAT|PIN_SCLK|PIN_SIN|PIN_GSCLK); P1OUT = 0x00; P2DIR |= (PIN_DCPRG|PIN_VPRG); P2OUT = 0x00; // initialize TLC5940 setLow(PORT_GSCLK, PIN_GSCLK); setLow(PORT_SCLK, PIN_SCLK); setLow(PORT_DCPRG, PIN_DCPRG); setHigh(PORT_VPRG, PIN_VPRG); setLow(PORT_XLAT, PIN_XLAT); setHigh(PORT_BLANK, PIN_BLANK); // force first cycle send_DC(); send_GS(); // enable interrupts __bis_SR_register(GIE); while(1) { // load gs-data here // update PWM-data permanently send_GS(); } }
×