MIDI Program Changer (2) Program Details – 1

I choosed an AT Mega 16 for this project, using Atmel Studio in C

atmega

So let’s have a look at the code mentionend (slightly simplfied).

  1. 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
}
}

Dieser Beitrag wurde unter Basteln, Mikrocontroller/Arduino veröffentlicht. Setze ein Lesezeichen auf den Permalink.

Ein Kommentar zu MIDI Program Changer (2) Program Details – 1

  1. Werner Sengpiel sagt:

    Thanks , I hope I can it Transfer to my Controller.
    Werner

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.