Guest User

Untitled

a guest
May 26th, 2018
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.98 KB | None | 0 0
  1. /*
  2.  * RS232 to TDA5940 Synced data transfer.
  3.  * Reads channel data from RS232 and writes it to SPI connected TDA5940 devices
  4.  * It keeps the TDA5940 running by periodically creating a pulse on the BLANK line.
  5.  * When all new data has been written it is latched in during blank period.
  6.  *
  7.  * (c) 2012 Philipp Claves licensed under GPLv2 or later
  8.  */
  9.  
  10.  
  11. #include <avr/io.h>
  12. #include <avr/interrupt.h>
  13. #define F_CPU 20000000
  14. #define BAUD 115200
  15.  
  16. /**
  17.  * Initialize the UART, Frame format 8-N-1
  18.  */
  19. void uart_init(void){
  20.     #include <util/setbaud.h>
  21.     UBRR0H = UBRRH_VALUE;
  22.     UBRR0L = UBRRL_VALUE;
  23.     #if USE_2X
  24.         UCSR0A |= (1 << U2X0);
  25.     #else
  26.         UCSR0A &= ~(1 << U2X0);
  27.     #endif
  28.    
  29.     //Set frame format
  30.     UCSR0C = (1<<UCSZ00) | (1<<UCSZ01); // | (1<<URSEL); //8 data bits, 1 stop bit no parity (URSEL is an ATMega specific fuckup)
  31.     //Enable receiver and transmitter.
  32.     UCSR0B = (1<<RXEN0) | (1<<TXEN0);
  33. }
  34.  
  35. /**
  36.  * Initialize the SPI in Master mode, freq = f_cpu/2
  37.  */
  38. void spi_init(void){
  39.     // Set SS, MOSI and SCK output
  40.     DDRB |= (1<<PB5) | (1<<PB7) | (1<<PB4);
  41.     // Enable SPI, Master, MSB first, set clock rate fck/2
  42.     SPCR = (1<<SPE) | (1<<MSTR);
  43.     SPSR = (1<<SPI2X);
  44. }
  45.  
  46. #define TLC5940_N 1  //Number of chained TLC5940 chips
  47.  
  48. #define DCPROG_PORT PORTD
  49. #define DCPROG_DDR  DDRD
  50. #define DCPROG_LINE (1 << PD6)  //DC Program pin: PD6
  51. #define VPROG_PORT  PORTD
  52. #define VPROG_DDR   DDRD
  53. #define VPROG_LINE  (1 << PD7)  //DC Program pin: PD7
  54.  
  55. #define DC_DATA_SIZE (12 * TLC5940_N)
  56. typedef uint8_t tlc5940_dc_data_t[DC_DATA_SIZE];
  57.  
  58. #define GS_DATA_SIZE (24 * TLC5940_N)
  59. typedef uint8_t tlc5940_gs_data_t[GS_DATA_SIZE];
  60.  
  61. void tlc5940_init(void){
  62.     DCPROG_DDR |= DCPROG_LINE;
  63.     VPROG_DDR  |= VPROG_LINE;
  64. }
  65.  
  66. #define BLANK_DDR        DDRD
  67. #define BLANK_LINE       (1 << PD4) //Blank pulse pin: PD4
  68. #define BLANK_OCR        OCR1B
  69. #define BLANK_INT_ENABLE (1 << OCIE1B)
  70. #define LATCH_INT_FLAG   (1 << OCF1A)
  71. #define BLANK_INT_VECT   TIMER1_COMPB_vect
  72. #define LATCH_DDR        DDRD
  73. #define LATCH_LINE       (1 << PD5) //Latch pulse pin: PD5
  74. #define LATCH_OCR        OCR1A
  75. #define LATCH_INT_ENABLE (1 << OCIE1A)
  76. #define LATCH_INT_FLAG   (1 << OCF1A)
  77. #define LATCH_INT_VECT   TIMER1_COMPA_vect
  78. #define BLANK_INT_ENABLE (1 << OCIE1B)
  79. #define BLANK_INT_FLAG   (1 << OCF1B)
  80. #define BLANK_INT_VECT   TIMER1_COMPB_vect
  81.  
  82.  
  83. /**
  84.  * Initialize the timer to gernate blanking and latching pulses
  85.  * The timer is set to 10 bit PWM with no prescaler to generate a blanking pulse of
  86.  * 2 clock cyles length every 1024 clock cyles. The blanking is enabled.
  87.  * The latching pulse is configured to be 1 clock cyle in length and is diables by default.
  88.  * To activate the latching pulse, set the LATCH_LINE pin on LATCH_DDR to output (1)
  89.  * Timer interrupts are NOT enabled.
  90.  */
  91. void timer_init(void){
  92.     TCCR1A = (1 << WGM10) | (1 << WGM11) //Fast PWM 10bit
  93.            | (1 << COM1A1)               //Clear A on compare match;
  94.            | (1 << COM1B1);              //Clear B on compare match;
  95.     TCCR1B = (1 << WGM12)                //Fast PWM 10bit
  96.            | (1 << CS10);   //Clock source cpu (no prescaler)
  97.    
  98.     LATCH_OCR = 0; //Latch pulse, shorter than blaking
  99.     BLANK_OCR = 1; //Blanking pulse
  100.    
  101.     BLANK_DDR |= BLANK_LINE;  //Enable Blanking pulse
  102. }
  103.  
  104. /**
  105.  * Set to 1 once the latching occurs.
  106.  * Due to the interrupt context switch delay this happens about
  107.  * 2µS (at 12Mhz) AFTER the latching pulse has ended.
  108.  */
  109. volatile uint8_t latch_done;
  110. volatile uint8_t send_done;
  111. volatile uint8_t rx_buffer[GS_DATA_SIZE];
  112.  
  113. /**
  114.  * Latching interrupt handler.
  115.  * If enabled it will set the latch_done flag and disable the Lachting pulse as well as itself.
  116.  * NOTE: Any timer1 iterrupt could be used here, handling them takes longer than
  117.  *       both latching and blanking pulse do.
  118.  */
  119. ISR(LATCH_INT_VECT){
  120.     PORTB |=  (1 << 0);     //Debug output
  121.     latch_done = 1;           //Set latch done flag
  122.     LATCH_DDR &= ~LATCH_LINE; //Disable latching pulse output
  123.     TIMSK1 = 0;                //Disable timerinterrupt
  124.     PORTB &= ~(1 << 0);     //Debug output
  125. }
  126.  
  127.  
  128.  
  129. /**
  130.  * Enables the latching pulse to fire once and load the data into the TDA5940.
  131.  * It waits for the latching pulse to occur, so that new data
  132.  * can be safely written to SPI.
  133.  * NOTE: Waiting might not be needed here because the UART is slow
  134.  *       but better safe than sorry.
  135.  */
  136. void do_latch_wait(void){
  137.     latch_done = 0;           //Clear latch flag. To be set by timer interrupt
  138.     LATCH_DDR |= LATCH_LINE;  //Enable latching pulse output
  139.     TIFR1  = LATCH_INT_FLAG;   //Clear interrupt flag before enabling timer interrupt
  140.     TIMSK1 = LATCH_INT_ENABLE; //Enable the timer overflow interrupt
  141.     while (!latch_done) {;}   //Wait for latch to be done
  142. }
  143.  
  144. ISR(BLANK_INT_VECT){
  145.     for(uint8_t tx_pos = 0; tx_pos < 24; tx_pos++){
  146.         SPDR = rx_buffer[tx_pos];
  147.         while (!(SPSR & (1 << SPIF)));
  148.     }
  149.     send_done = 1;
  150. }
  151.  
  152.  
  153. void tlc5940_write_dc_data(tlc5940_dc_data_t data){
  154.     VPROG_PORT  |= VPROG_LINE;
  155.     DCPROG_PORT |= DCPROG_LINE;
  156.    
  157.     for (uint8_t i = 0; i < DC_DATA_SIZE; i++){
  158.         while (!(SPSR & (1 << SPIF)));
  159.         SPDR = data[i];
  160.     }
  161.     while (!(SPSR & (1 << SPIF)));
  162.    
  163.     DCPROG_PORT &= ~DCPROG_LINE;
  164.     VPROG_PORT  &= ~VPROG_LINE;
  165. }
  166.  
  167. int main(void){
  168.     uint8_t rx_pos;
  169.    
  170.     uart_init();
  171.     spi_init();
  172.     tlc5940_init();
  173.     timer_init();
  174.     sei();
  175.    
  176.     DDRB |= (1 << 0); //Debug output
  177.    
  178.    
  179.    
  180.     while(1) {
  181.        
  182.         PORTB |= (1 << 0);
  183.         while ( !( UCSR0A & (1 << UDRE0)) ) {;} //Wait for empty UART transmit buffer
  184.         UDR0 = 'R'; //Send ready status
  185.         PORTB &= ~(1 << 0);
  186.        
  187.         //Receive data from UART and Write it to SPI
  188.         for (rx_pos = 0; rx_pos < GS_DATA_SIZE; rx_pos++){ //Transfer 10 bytes
  189.             while ((UCSR0A & (1 << RXC0)) == 0) {;} //Wait for UART Data
  190. //          SPDR = UDR0; //Write data to SPI
  191.             rx_buffer[rx_pos] = UDR0;
  192.         }
  193.         UDR0 = 'A'; //Ack data receive
  194.  
  195.         send_done = 0;
  196.  
  197.         TIFR1  = BLANK_INT_FLAG;   //Clear interrupt flag before enabling timer interrupt
  198.         TIMSK1 = BLANK_INT_ENABLE;
  199.  
  200.         while(send_done == 0){;}
  201.        
  202.         do_latch_wait(); //Latch data into TDA5940
  203.     }
  204. }
Add Comment
Please, Sign In to add comment