My journey with ATTiny4313 (part 3)

Part 3: More than blinking

Adding MIDI

Adding the configuration of USART is straightforward.

   ...
; =========================================================
; Main routine
; =========================================================
main:
   ...
; ---------------------------------
; Configuration of USART for MIDI
; ---------------------------------
   ldi   r16,   (1<<UDRE)
   STORE UCSRA, r16       ; Asynchronous Normal mode, buffer empty
   ldi   r16,   (1<<TXEN)
   STORE UCSRB, r16       ; Enable the transmitter, but not the receiver
   ldi   r16,   (1<<UCSZ1|1<<UCSZ0)
   STORE UCSRC, r16       ; 8 bits, no parity, 1 stop bit
   ; Setting the speed to 31250 bauds
   ; UBRR =  (fosc / 16 * BAUD) - 1
   ;      = (8000000 / 16 * 31250) - 1
   ;      = 15 = 0x0f
   ldi   r16,   0x00
   STORE UBRRH, r16
   ldi   r16,   0x0f
   STORE UBRRL, r16
After the loop, we check the LOOP LED; if the LED is off, we send a MIDI NOTE ON and light on the LED. Otherwise, we send a NOTE OFF and light off the LED.
  
   ...
oloop:
   ...
   brne	oloop
   
   sbic  PORTD, LOOP_LED  ; Is LOOP_LED = 0 ?
   rjmp  load_note        ; Yes: load a new note
   rcall note_off         ; Otherwise, send NOTE OFF
   rjmp	 oloop

load_note:
   ldi   r20, 0x25   ; The note number
   rcall note_on     ; Call NOTE ON
   rjmp  oloop       ; Restart the loop
This is the code send the 3 bytes of a note on MIDI message: NOTE ON, note number and velocity.
note_on:              ; Send a note on
   ldi   r23, NOTE_ON ; Note on
   rcall midi_send
   mov   r23, r20
   rcall midi_send
   ldi   r23, 0x60    ; Mid velocity
   rcall midi_send
   ret
This is the code send the 3 bytes of a note off MIDI message: NOTE OFF, note number and null velocity.
note_off:              ; Send a note off
   ldi   r23, NOTE_OFF ; Note off
   rcall midi_send
   mov   r23, r20
   rcall midi_send
   ldi   r23, 0x00     ; 0 velocity
   rcall midi_send
   ret
The midi_send function waits for buffer to be empty.
midi_send:	; Send the MIDI byte in r23, start the timer 1 and light up the MIDI activity LED
	cli			; Disable interrupts
	; ---- send the MIDI byte
wait_usart:
	sbis	UCSRA, UDRE	; Wait USART Data Register empty
	rjmp	wait_usart
	STORE	UDR, r23	; Store the byte in r23 to the USART Data Register
	; ---- Reset the TCNT1 counter
	clr	r16
	clr	r17
	STORE	TCNT1H,	r16
	STORE	TCNT1L,	r17
	; ---- Start the timer by setting prescaler = 1024
	ldi	r16,	(1<<WGM12)|(1<<CS10)|(1<<CS12)
	STORE	TCCR1B,	r16
	; ---- Light the MIDI LED on
	LOAD	r16,	PORTD
	sbr	r16,	(1<<MIDI_LED)
	STORE	PORTD, 	r16
	sei			; Enable interrupts
	ret

MIDI Codes

Channel messages

Hex Binary Description Param #1 Param #2
0x8x 1000 cccc Note-off key # velocity
0x9x 1001 cccc Note-on key # velocity
0xAx 1010 cccc Aftertouch key # value
0xBx 1011 cccc Continuous Controller Controller # value
0xCx 1100 cccc Patch change Patch #
0xDx 1101 cccc Channel Pressure Value
0xEx 1110 cccc Pitch bend Value LSB Value MSB

System messages

Hex Binary Description Param #1 Param #2
0xF0 1111 0000 Start of System exclusive message Vendor ID Variable length
0xF1 1111 0001 MIDI Time Code Quarter Frame
Binary Description
0000 ffff Piece 0: Frame number lsbits
0001 000f Piece 1: Frame number msbit
0010 ssss Piece 2: Second lsbits
0011 00ss Piece 3: Second msbits
0100 mmmm Piece 4: Minute lsbits
0101 00mm Piece 5: Minute msbits
0110 hhhh Piece 6: Hour lsbits
0111 0rrh Piece 7: Rate and hour msbit
0xF2 1111 0010 Song Position Pointer Value LSB Value MSB
0xF3 1111 0011 Song Select Song #
0xF4 1111 0100 Reserved
0xF5 1111 0101 Reserved
0xF6 1111 0110 Tune Request
0xF7 1111 0111 End of System exclusive message

Realtime messages

Hex Binary Description Param #1 Param #2
0xF8 1111 1000 Timing Clock
0xF9 1111 1001 Reserved
0xFA 1111 1010 Start
0xFB 1111 1011 Continue
0xFC 1111 1100 Stop
0xFD 1111 1101 Reserved
0xFE 1111 1110 Active Sensing
0xFF 1111 1111 System Reset

The issue

During the development of this project, a potential issue arose: the reset signal sent the Atari. In short, before sending data, the Atari pulses the /STROBE signal high to low 4 times; this is a signal for the CPLD of the original MO4 to reset. These pulses are sent at the speed of CPU (8 MHz); since my ATTiny runs also at 8MHz, I simply don't have enough time to process them, hence to detect a request to reset. I have to find an external way to process the pulses.
I came with 4 ranges of solution, but so far, no real solution. This will have to be developped.

  • Using a faster processor with 4 USART such as the ATXmega range (ex: ATxmega128A4U)
  • Using a Raspberry Pi Pico to dialog with the Atari, the ATTiny will be used only for the USART
  • Using an external counter, such as SN74ALS576BN (quadruple D flip-flops, negative edge, with preset and clear). This solution is simple and cheap.
  • Using an analog processing such as quickly discharging a capacitor on each pulse down, but slowly charging. The 4 successive discharges will drain the capacitor, which can be used to block a transistor.

Comments

Popular Posts