I choosed an AT Mega 16 for this project, using Atmel Studio in C
So let’s have a look at the code mentionend (slightly simplfied).
- MIDI I/O
Read and write work with Buffers, so main() does not have to bother if bytes can be sent as quickly as main() „produces“ them and if bytes can be processed by main() as quickly as they are received. Buffers are ring buffers so they act as kind FIFO stacks
tx/rx_buffer is an array of uint8_t (= Byte) with length 32. This size is arbitrary – by design much less would be sufficient. There are 2 indices: write_index and read_index. When read_index equals write_index there is nothing to be done. Incomming Bytes are stored at rx_buffer[write_index], then write_index is incremented. If write_index is more than maximum index (array size -1) then it is set to zero (ring buffer). If write_index „reaches“ read_index this means an buffer overflow
, which is not handled here – of course this case shoukd not be ignored in industrial applications ;). It must be observed that the indices are save from inadvertent changing. In interrupt handler this is no problem as the only other place to change the index is main(). Vice versa index operations im main() must not be interrupted by ISR!
A MIDI Byte is received by the USART. Interrupt ist enabled and set to following routine:
ISR(USART_RXC_vect) { uint8_t received_byte; received_byte = UDR; // read byte from USART rx_buffer[rx_write_index++] = received_byte; // get received byte if (rx_write_index >= RX_BUFFER_SIZE){ // ring buffer index at top, reset to zero rx_write_index = 0; } if (rx_write_index == rx_read_index){ // ring buffer overflow TODO: Report Error } }
The corresponding part in main() is:
if (rx_read_index != rx_write_index){ // something received cli(); // dont't interrupt because of index! midibyte = rx_buffer[rx_read_index++]; // get received byte if (rx_read_index >= RX_BUFFER_SIZE){ // ring buffer: round robin rx_read_index = 0; } sei(); // interrupt enabled again
Sending a MIDI-Byte works vice versa. The interrupt handler is called when the USART send buffer is empty, so if a byte could be sent. Corresponding procedure to write the buffer is called by main().
ISR(USART_UDRE_vect) { if (tx_write_index != tx_read_index){ // there is something to send UDR = tx_buffer[tx_read_index++]; // send byte if (tx_read_index >= TX_BUFFER_SIZE) { // ring buffer tx_read_index = 0; } } else { // nothing to send UCSRB &= ~(1 << UDRIE); // turn off this interrupt source // can be reactivated by send routine later } } ... static void sendbyte(uint8_t data) { UCSRB &= ~(1 << UDRIE); // deactivate Interrupts for USART empty // so tx_read_indexed cannot be messed up while following lines tx_buffer[tx_write_index++] = data; if (tx_write_index >= TX_BUFFER_SIZE){ // ring buffer: index round robin tx_write_index = 0; } UCSRB |= (1 << UDRIE); // reactivate interrupt // interrupt might alos have been deactivated by interrupt routine if (tx_write_index == tx_read_index){ // TODO: buffer overflow } }
Thanks , I hope I can it Transfer to my Controller.
Werner