#define begin { #define end } #include #include #include unsigned int time0; unsigned int i; //RXC ISR variables unsigned char r_index; //current string index unsigned char r_buffer[16]; //input string unsigned char r_ready; //flag for receive done unsigned char r_char; //current character //TX empty ISR variables unsigned char t_index; //current string index unsigned char t_buffer[16]; //output string unsigned char t_ready; //flag for transmit done unsigned char t_char; //current character unsigned char msg_length, previous_length; unsigned char msg_buffer[8]; unsigned char msg_buffer_index; unsigned char msg_ready, p_ready; unsigned char msg_buffer_full; unsigned char data_buffer_full; unsigned char data_buffer[512]; unsigned int parallel_index; unsigned int data_index; unsigned char msg_ready_1; void task0(); void gets_int(); void puts_int(); void initialize(); void get_msg(); void load_data_buffer(); void get_msg_1(); void send_byte(void); //********************************************* void main() begin initialize(); // initialize the parallel bus while(p_ready == 0); PORTB.3 = 1; PORTC = 0xFF; p_ready = 0; PORTB.3 = 0; while(1) begin if (time0 == 0) task0(); // poll USART if (p_ready) send_byte(); // send parallel data if (msg_ready) get_msg(); // read rx buffer 0 message if (msg_ready_1) get_msg_1(); // read rx buffer 1 message if (msg_buffer_full) load_data_buffer(); // move read message to data buffer end end //********************************************************** void send_byte(void) begin // clear parallel interrupt line PORTB.3 = 1; // only start parallel transmission when the data buffer is full if (data_buffer_full) begin // load a byte to the parallel port PORTC = data_buffer[parallel_index]; parallel_index++; // if all bytes have been loaded if (parallel_index == 512) begin parallel_index = 0; // clear parallel index data_index = 0; // clear data index data_buffer_full = 0; // clear flag end p_ready = 0; // clear flag PORTB.3 = 0; // interrupt the other Mega32 - signal data is ready to read end end //********************************************************** void load_data_buffer() begin // if the buffer is not full if (data_buffer_full == 0) begin // load the received data into the buffer for (i = 0; i < msg_buffer_index; i++) begin data_buffer[data_index] = msg_buffer[i]; data_index++; end msg_buffer_full = 0; // clear flag // detect if the buffer is full if (data_index > 503) begin data_buffer_full = 1; // set flag parallel_index = 0; // clear parallel index end end end //********************************************************** void get_msg_1() begin if (msg_buffer_full == 0) begin // read message length previous_length = msg_length; msg_length = spi_read(0x75); msg_length = msg_length & 0x0f; // Only store a message if it is a different length than the previous message (and nonzero) // There should always be an 8-byte message, then 6-bytes, then 8, then 6, etc. // This check will maintain sector alignment on the SD card and will reduce the chance of having // bad data by half (if the 8-byte part is lost, its corresponding 6-byte part will be discarded // and the system will move on to the next full message. but if a 6-byte part is lost, the next // 8-bit part will be discarded, and the data will still be mismatched) if ((msg_length != previous_length) && (msg_length != 0)) begin // load message into msg_buffer for (i = 0; i < msg_length; i++) begin msg_buffer[i] = spi_read(0x76+i); end msg_buffer_index = msg_length; msg_buffer_full = 1; // set flag msg_ready_1 = 0; // clear flag end // reset RX1BF interrupt spi_bit_modify(0x2c,0x02,0x00); end end //********************************************************** void get_msg() begin if (msg_buffer_full == 0) begin // read message length previous_length = msg_length; msg_length = spi_read(0x65); msg_length = msg_length & 0x0f; // Only store a message if it is a different length than the previous message (and nonzero) if ((msg_length != previous_length) && (msg_length != 0)) begin // load message into msg_buffer for (i = 0; i < msg_length; i++) begin msg_buffer[i] = spi_read(0x66+i); end msg_buffer_index = msg_length; msg_buffer_full = 1; // set flag msg_ready = 0; // clear flag end // reset RX0BF interrupt spi_bit_modify(0x2c,0x01,0x00); end end //********************************************************** void task0() begin /* Input Format: L+ start listening for data stream L- stop listening */ time0 = 200; if (r_ready) begin switch(r_buffer[0]) begin case 'L': switch(r_buffer[1]) begin case '+': spi_write(0x0f,0x07); // normal operation mode // start listening for CAN messages spi_write(0x60,0x60); // no input filters or masks = receive all messages spi_write(0x0c,0x0f); // enable RX0BF and RX1BF as interrupts GICR |= 0b01100000; // enable external INT0 and INT2 break; case '-': // stop listening for CAN messages GICR &= 0b10011111; // disable external INT0 and INT2 break; end break; end gets_int(); end end //********************************************************** interrupt [EXT_INT0] void extint0(void) begin msg_ready = 1; // set flag end //********************************************************** interrupt [EXT_INT2] void extint2(void) begin msg_ready_1 = 1; // set flag end //********************************************************** interrupt [EXT_INT1] void extint1(void) begin p_ready = 1; // set flag end //********************************************************** interrupt [TIM0_COMP] void timer0(void) begin // counter decrement if (time0 > 0) time0--; end //********************************************* void initialize() begin // trigger external INT0 in falling edge of INT0 (MCUCR.1,0 = 10) // trigger external INT1 in falling edge of INT1 (MCUCR.3,2 = 10) MCUCR |= 0x0A; GICR = 0b10000000; // SPI ISR disabled, SPI enabled, MSB first, master, SCK = 8MHz SPCR = 0b01010000; SPSR.0 = 1; // set up USART, 9600 baud, Tx and Rx enabled, RxC ISR enabled UBRRL = 103; UCSRB = 0b10011000; // timer0 compare match ISR slower than every 1ms TCCR0 = 0b00001100; OCR0 = 249; TCNT0 = 0; TIMSK = 0b00000010; // D.1 output for TXD, D.0 input for RXD // D.3 is input for INT1 DDRD = 0b00000010; // B.7 output SCK, B.6 input MISO, B.5 output MOSI, B.4 output CS for CAN, B.3 for parallel interrupt DDRB = 0b10111010; DDRC = 0xFF; //Port C is the parallel output port // initialize chip select high PORTB.4 = 1; PORTB.3 = 0; // INTs pulled up PORTB.2 = 1; // INT2 PORTD.3 = 1; // INT1 PORTD.2 = 1; // INT0 // no strings received, ready to transmit r_ready = 0; t_ready = 1; p_ready = 0; time0 = 200; data_index = 0; data_buffer_full = 0; #asm("sei") end //********************************************************** //UART xmit-empty ISR interrupt [USART_DRE] void uart_send(void) begin t_char = t_buffer[++t_index]; if (t_char == 0) begin UCSRB.5=0; //kill isr t_ready=1; //transmit done end else UDR = t_char ; //send the char end //********************************************************** //UART character-ready ISR interrupt [USART_RXC] void uart_rec(void) begin r_char=UDR; //get a char UDR=r_char; //then print it //build the input string if (r_char != '\r') r_buffer[r_index++]=r_char; else begin putchar('\n'); //use putchar to avoid overwrite r_buffer[r_index]=0x00; //zero terminate r_ready=1; //signal cmd processor UCSRB.7=0; //stop rec ISR end end //********************************************************** // -- non-blocking keyboard check initializes ISR-driven // receive. This routine merely sets up the ISR, which then //does all the work of getting a command. void gets_int(void) begin r_ready=0; r_index=0; UCSRB.7=1; end //********************************************************** // -- nonblocking print: initializes ISR-driven // transmit. This routine merely sets up the ISR, then //send one character, The ISR does all the work. void puts_int(void) begin t_ready=0; t_index=0; if (t_buffer[0]>0) begin putchar(t_buffer[0]); UCSRB.5=1; end end //**********************************************************