Labrador/AVR_Code/USB_BULK_TEST/src/tiny_dma.c

678 lines
28 KiB
C

/*
* tiny_dma.c
*
* Created: 25/06/2015 9:00:42 AM
* Author: Esposch
*/
#include "tiny_dma.h"
#include "tiny_adc.h"
#include "tiny_uart.h"
#include "tiny_calibration.h"
#include "globals.h"
#include "util/delay.h"
#ifndef SINGLE_ENDPOINT_INTERFACE
#define DMA_STANDARD_INTERRUPT (0x00)
#define DMA_STANDARD_CTRLA (DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm)
#define DMA_STANDARD_TRANSFER_LENGTH (PACKET_SIZE)
#else
#define DMA_STANDARD_INTERRUPT (0x03)
#define DMA_STANDARD_CTRLA (DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm)
#define DMA_STANDARD_TRANSFER_LENGTH (HALFPACKET_SIZE)
#endif
void tiny_dma_setup(void){
//Turn on DMA
PR.PRGEN &=0b111111110; //Turn on DMA clk
#ifndef SINGLE_ENDPOINT_INTERFACE
DMA.CTRL = DMA_ENABLE_bm | DMA_PRIMODE_CH0123_gc;
#else
DMA.CTRL = DMA_ENABLE_bm | DMA_PRIMODE_RR0123_gc;
#warning "Round Robin on DMA"
#endif
}
void tiny_dma_flush(void){
DMA.CH0.CTRLA = 0x00;
DMA.CH0.CTRLA = DMA_CH_RESET_bm;
DMA.CH1.CTRLA = 0x00;
DMA.CH1.CTRLA = DMA_CH_RESET_bm;
DMA.CH2.CTRLA = 0x00;
DMA.CH2.CTRLA = DMA_CH_RESET_bm;
DMA.CH3.CTRLA = 0x00;
DMA.CH3.CTRLA = DMA_CH_RESET_bm;
b1_state = 0;
b2_state = 0;
usb_state = 0;
dma_ch0_ran = 0;
dma_ch1_ran = 0;
}
void tiny_dma_delayed_set(unsigned char mode){
futureMode = mode;
modeChanged = 1;
}
void tiny_dma_set_mode_0(void){
global_mode = 0;
tiny_dma_flush();
DMA.CH2.REPCNT = 0; //Repeat forever!
DMA.CH2.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm;
DMA.CH2.CTRLB = 0x00; //No interrupt for DacBuf!!
DMA.CH2.ADDRCTRL = DMA_CH_DESTRELOAD_BURST_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_SRCRELOAD_BLOCK_gc | DMA_CH_SRCDIR_INC_gc; //Dest reloads after each burst, with byte incrementing. Src reloads at end of block, also incrementing address.
DMA.CH2.TRIGSRC = DMA_CH_TRIGSRC_EVSYS_CH1_gc; //Triggered from TCC0 when it hits PER
DMA.CH2.TRFCNT = auxDacBufLen;
DMA.CH2.SRCADDR0 = (( (uint16_t) &dacBuf_CH2[0]) >> 0) & 0xFF; //Source address is dacbuf
DMA.CH2.SRCADDR1 = (( (uint16_t) &dacBuf_CH2[0]) >> 8) & 0xFF;
DMA.CH2.SRCADDR2 = 0x00;
DMA.CH2.DESTADDR0 = (( (uint16_t) &DACB.CH1DATAH) >> 0) & 0xFF; //Dest address is high byte of DAC register
DMA.CH2.DESTADDR1 = (( (uint16_t) &DACB.CH1DATAH) >> 8) & 0xFF;
DMA.CH2.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
DMA.CH2.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
DMA.CH3.REPCNT = 0; //Repeat forever!
DMA.CH3.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm;
DMA.CH3.CTRLB = 0x00; //Hi interrupt on block complete
DMA.CH3.ADDRCTRL = DMA_CH_DESTRELOAD_BURST_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_SRCRELOAD_BLOCK_gc | DMA_CH_SRCDIR_INC_gc; //Dest reloads after each burst, with byte incrementing. Src reloads at end of block, also incrementing address.
DMA.CH3.TRIGSRC = DMA_CH_TRIGSRC_EVSYS_CH2_gc; //Triggered from TCC0 when it hits PER
DMA.CH3.TRFCNT = dacBuf_len;
DMA.CH3.SRCADDR0 = (( (uint16_t) &dacBuf_CH1[0]) >> 0) & 0xFF; //Source address is dacbuf
DMA.CH3.SRCADDR1 = (( (uint16_t) &dacBuf_CH1[0]) >> 8) & 0xFF;
DMA.CH3.SRCADDR2 = 0x00;
DMA.CH3.DESTADDR0 = (( (uint16_t) &DACB.CH0DATAH) >> 0) & 0xFF; //Dest address is high byte of DAC register
DMA.CH3.DESTADDR1 = (( (uint16_t) &DACB.CH0DATAH) >> 8) & 0xFF;
DMA.CH3.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
DMA.CH3.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
DMA.CH0.CTRLA = 0x00;
DMA.CH0.CTRLA = DMA_CH_RESET_bm;
DMA.CH0.CTRLA = DMA_STANDARD_CTRLA;
DMA.CH0.CTRLB = DMA_STANDARD_INTERRUPT;
DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_BURST_gc | DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_DESTRELOAD_BLOCK_gc; //Source reloads after each burst, with byte incrementing. Dest does not reload, but does increment address.
DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_ADCA_CH0_gc; //Triggered from ADCA channel 0
DMA.CH0.TRFCNT = DMA_STANDARD_TRANSFER_LENGTH;
DMA.CH0.SRCADDR0 = (( (uint16_t) &ADCA.CH0.RESL) >> 0) & 0xFF; //Source address is ADC
DMA.CH0.SRCADDR1 = (( (uint16_t) &ADCA.CH0.RESL) >> 8) & 0xFF;
DMA.CH0.SRCADDR2 = 0x00;
DMA.CH0.DESTADDR0 = (( (uint16_t) &isoBuf[0]) >> 0) & 0xFF; //Dest address is isoBuf
DMA.CH0.DESTADDR1 = (( (uint16_t) &isoBuf[0]) >> 8) & 0xFF;
DMA.CH0.DESTADDR2 = 0x00;
tiny_calibration_synchronise_phase(500, 200);
median_TRFCNT = 200;
median_TRFCNT_delay = 1; //Wait a few frames before actually setting median_TRFCNT, in case a SOF interrupt was queued during tiny_dma_set_mode_xxx.
DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
}
void tiny_dma_loop_mode_0(void){
return;
}
void tiny_dma_set_mode_1(void){
global_mode = 1;
tiny_dma_flush();
//AUX channel (to keep it tx, therefore always rx)
DMA.CH2.CTRLA = 0x00;
DMA.CH2.CTRLA = DMA_CH_RESET_bm;
DMA.CH2.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm; //Do not repeat!
DMA.CH2.CTRLB = 0x00; //No int
DMA.CH2.ADDRCTRL = DMA_CH_SRCDIR_FIXED_gc | DMA_CH_DESTDIR_FIXED_gc; //Source and address fixed.
DMA.CH2.TRIGSRC = DMA_CH_TRIGSRC_USARTC0_RXC_gc;
DMA.CH2.TRFCNT = 0;
DMA.CH2.REPCNT = 0;
DMA.CH2.SRCADDR0 = (( (uint16_t) &dummy) >> 0) & 0xFF;
DMA.CH2.SRCADDR1 = (( (uint16_t) &dummy) >> 8) & 0xFF;
DMA.CH2.SRCADDR2 = 0x00;
DMA.CH2.DESTADDR0 = (( (uint16_t) &USARTC0.DATA) >> 0) & 0xFF;
DMA.CH2.DESTADDR1 = (( (uint16_t) &USARTC0.DATA) >> 8) & 0xFF;
DMA.CH2.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
DMA.CH2.CTRLA |= DMA_CH_REPEAT_bm | DMA_CH_ENABLE_bm; //Enable!
USARTC0.DATA = 0x55;
USARTC0.DATA = 0x55;
DMA.CH3.REPCNT = 0; //Repeat forever!
DMA.CH3.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm;
DMA.CH3.CTRLB = 0x00; //No interrupt for DacBuf!!
DMA.CH3.ADDRCTRL = DMA_CH_DESTRELOAD_BURST_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_SRCRELOAD_BLOCK_gc | DMA_CH_SRCDIR_INC_gc; //Dest reloads after each burst, with byte incrementing. Src reloads at end of block, also incrementing address.
DMA.CH3.TRIGSRC = DMA_CH_TRIGSRC_EVSYS_CH1_gc; //Triggered from TCC0 when it hits PER
DMA.CH3.TRFCNT = auxDacBufLen;
DMA.CH3.SRCADDR0 = (( (uint16_t) &dacBuf_CH2[0]) >> 0) & 0xFF; //Source address is dacbuf
DMA.CH3.SRCADDR1 = (( (uint16_t) &dacBuf_CH2[0]) >> 8) & 0xFF;
DMA.CH3.SRCADDR2 = 0x00;
DMA.CH3.DESTADDR0 = (( (uint16_t) &DACB.CH1DATAH) >> 0) & 0xFF; //Dest address is high byte of DAC register
DMA.CH3.DESTADDR1 = (( (uint16_t) &DACB.CH1DATAH) >> 8) & 0xFF;
DMA.CH3.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
DMA.CH3.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
DMA.CH1.CTRLA = DMA_STANDARD_CTRLA;
DMA.CH1.CTRLB = DMA_STANDARD_INTERRUPT;
DMA.CH1.ADDRCTRL = DMA_CH_SRCRELOAD_BURST_gc | DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_DESTRELOAD_BLOCK_gc; //Source reloads after each burst, with byte incrementing. Dest does not reload, but does increment address.
DMA.CH1.TRIGSRC = DMA_CH_TRIGSRC_USARTC0_RXC_gc;
DMA.CH1.TRFCNT = DMA_STANDARD_TRANSFER_LENGTH;
DMA.CH1.SRCADDR0 = (( (uint16_t) &USARTC0.DATA) >> 0) & 0xFF;
DMA.CH1.SRCADDR1 = (( (uint16_t) &USARTC0.DATA) >> 8) & 0xFF;
DMA.CH1.SRCADDR2 = 0x00;
DMA.CH1.DESTADDR0 = (( (uint16_t) &isoBuf[PACKET_SIZE]) >> 0) & 0xFF; //Dest address is isoBuf
DMA.CH1.DESTADDR1 = (( (uint16_t) &isoBuf[PACKET_SIZE]) >> 8) & 0xFF;
DMA.CH1.DESTADDR2 = 0x00;
DMA.CH0.CTRLA = DMA_STANDARD_CTRLA;
DMA.CH0.CTRLB = DMA_STANDARD_INTERRUPT;
DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_BURST_gc | DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_DESTRELOAD_BLOCK_gc; //Source reloads after each burst, with byte incrementing. Dest does not reload, but does increment address.
DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_ADCA_CH0_gc; //Triggered from ADCA channel 0
DMA.CH0.TRFCNT = DMA_STANDARD_TRANSFER_LENGTH;
DMA.CH0.SRCADDR0 = (( (uint16_t) &ADCA.CH0.RESL) >> 0) & 0xFF; //Source address is ADC
DMA.CH0.SRCADDR1 = (( (uint16_t) &ADCA.CH0.RESL) >> 8) & 0xFF;
DMA.CH0.SRCADDR2 = 0x00;
DMA.CH0.DESTADDR0 = (( (uint16_t) &isoBuf[0]) >> 0) & 0xFF; //Dest address is isoBuf
DMA.CH0.DESTADDR1 = (( (uint16_t) &isoBuf[0]) >> 8) & 0xFF;
DMA.CH0.DESTADDR2 = 0x00;
tiny_calibration_synchronise_phase(500, 200);
median_TRFCNT = 200;
median_TRFCNT_delay = 1; //Wait a few frames before actually setting median_TRFCNT, in case a SOF interrupt was queued during tiny_dma_set_mode_xxx.
DMA.CH1.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
}
void tiny_dma_loop_mode_1(void){
return;
}
void tiny_dma_set_mode_2(void){
global_mode = 2;
tiny_dma_flush();
DMA.CH2.REPCNT = 0; //Repeat forever!
DMA.CH2.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm;
DMA.CH2.CTRLB = 0x00; //No interrupt for DacBuf!!
DMA.CH2.ADDRCTRL = DMA_CH_DESTRELOAD_BURST_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_SRCRELOAD_BLOCK_gc | DMA_CH_SRCDIR_INC_gc; //Dest reloads after each burst, with byte incrementing. Src reloads at end of block, also incrementing address.
DMA.CH2.TRIGSRC = DMA_CH_TRIGSRC_EVSYS_CH1_gc; //Triggered from TCC0 when it hits PER
DMA.CH2.TRFCNT = auxDacBufLen;
DMA.CH2.SRCADDR0 = (( (uint16_t) &dacBuf_CH2[0]) >> 0) & 0xFF; //Source address is dacbuf
DMA.CH2.SRCADDR1 = (( (uint16_t) &dacBuf_CH2[0]) >> 8) & 0xFF;
DMA.CH2.SRCADDR2 = 0x00;
DMA.CH2.DESTADDR0 = (( (uint16_t) &DACB.CH1DATAH) >> 0) & 0xFF; //Dest address is high byte of DAC register
DMA.CH2.DESTADDR1 = (( (uint16_t) &DACB.CH1DATAH) >> 8) & 0xFF;
DMA.CH2.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
DMA.CH2.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
DMA.CH3.REPCNT = 0; //Repeat forever!
DMA.CH3.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm;
DMA.CH3.CTRLB = 0x00; //Hi interrupt on block complete
DMA.CH3.ADDRCTRL = DMA_CH_DESTRELOAD_BURST_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_SRCRELOAD_BLOCK_gc | DMA_CH_SRCDIR_INC_gc; //Dest reloads after each burst, with byte incrementing. Src reloads at end of block, also incrementing address.
DMA.CH3.TRIGSRC = DMA_CH_TRIGSRC_EVSYS_CH2_gc; //Triggered from TCC0 when it hits PER
DMA.CH3.TRFCNT = dacBuf_len;
DMA.CH3.SRCADDR0 = (( (uint16_t) &dacBuf_CH1[0]) >> 0) & 0xFF; //Source address is dacbuf
DMA.CH3.SRCADDR1 = (( (uint16_t) &dacBuf_CH1[0]) >> 8) & 0xFF;
DMA.CH3.SRCADDR2 = 0x00;
DMA.CH3.DESTADDR0 = (( (uint16_t) &DACB.CH0DATAH) >> 0) & 0xFF; //Dest address is high byte of DAC register
DMA.CH3.DESTADDR1 = (( (uint16_t) &DACB.CH0DATAH) >> 8) & 0xFF;
DMA.CH3.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
DMA.CH3.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
DMA.CH0.CTRLA = 0x00;
DMA.CH0.CTRLA = DMA_CH_RESET_bm;
DMA.CH0.CTRLA = DMA_STANDARD_CTRLA;
DMA.CH0.CTRLB = DMA_STANDARD_INTERRUPT;
DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_BURST_gc | DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_DESTRELOAD_BLOCK_gc; //Source reloads after each burst, with byte incrementing. Dest does not reload, but does increment address.
DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_ADCA_CH0_gc; //Triggered from ADCA channel 0
DMA.CH0.TRFCNT = DMA_STANDARD_TRANSFER_LENGTH;
DMA.CH0.SRCADDR0 = (( (uint16_t) &ADCA.CH0.RESL) >> 0) & 0xFF; //Source address is ADC
DMA.CH0.SRCADDR1 = (( (uint16_t) &ADCA.CH0.RESL) >> 8) & 0xFF;
DMA.CH0.SRCADDR2 = 0x00;
DMA.CH0.DESTADDR0 = (( (uint16_t) &isoBuf[0]) >> 0) & 0xFF; //Dest address is isoBuf
DMA.CH0.DESTADDR1 = (( (uint16_t) &isoBuf[0]) >> 8) & 0xFF;
DMA.CH0.DESTADDR2 = 0x00;
DMA.CH1.CTRLA = DMA_STANDARD_CTRLA;
DMA.CH1.CTRLB = DMA_STANDARD_INTERRUPT;
DMA.CH1.ADDRCTRL = DMA_CH_SRCRELOAD_BURST_gc | DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_DESTRELOAD_BLOCK_gc; //Source reloads after each burst, with byte incrementing. Dest does not reload, but does increment address.
DMA.CH1.TRIGSRC = DMA_CH_TRIGSRC_ADCA_CH0_gc; //Triggered from ADCA channel 0
DMA.CH1.TRFCNT = DMA_STANDARD_TRANSFER_LENGTH;
DMA.CH1.SRCADDR0 = (( (uint16_t) &ADCA.CH2.RESL) >> 0) & 0xFF; //Source address is ADC
DMA.CH1.SRCADDR1 = (( (uint16_t) &ADCA.CH2.RESL) >> 8) & 0xFF;
DMA.CH1.SRCADDR2 = 0x00;
DMA.CH1.DESTADDR0 = (( (uint16_t) &isoBuf[PACKET_SIZE]) >> 0) & 0xFF; //Dest address is isoBuf
DMA.CH1.DESTADDR1 = (( (uint16_t) &isoBuf[PACKET_SIZE]) >> 8) & 0xFF;
DMA.CH1.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
tiny_calibration_synchronise_phase(500, 200);
median_TRFCNT = 200;
median_TRFCNT_delay = 1; //Wait a few frames before actually setting median_TRFCNT, in case a SOF interrupt was queued during tiny_dma_set_mode_xxx.
DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
DMA.CH1.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
}
void tiny_dma_loop_mode_2(void){
return;
}
void tiny_dma_set_mode_3(void){
global_mode = 3;
tiny_dma_flush();
DMA.CH3.REPCNT = 0; //Repeat forever!
DMA.CH3.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm;
DMA.CH3.CTRLB = 0x00; //No interrupt for DacBuf!!
DMA.CH3.ADDRCTRL = DMA_CH_DESTRELOAD_BURST_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_SRCRELOAD_BLOCK_gc | DMA_CH_SRCDIR_INC_gc; //Dest reloads after each burst, with byte incrementing. Src reloads at end of block, also incrementing address.
DMA.CH3.TRIGSRC = DMA_CH_TRIGSRC_EVSYS_CH1_gc; //Triggered from TCC0 when it hits PER
DMA.CH3.TRFCNT = auxDacBufLen;
DMA.CH3.SRCADDR0 = (( (uint16_t) &dacBuf_CH2[0]) >> 0) & 0xFF; //Source address is dacbuf
DMA.CH3.SRCADDR1 = (( (uint16_t) &dacBuf_CH2[0]) >> 8) & 0xFF;
DMA.CH3.SRCADDR2 = 0x00;
DMA.CH3.DESTADDR0 = (( (uint16_t) &DACB.CH1DATAH) >> 0) & 0xFF; //Dest address is high byte of DAC register
DMA.CH3.DESTADDR1 = (( (uint16_t) &DACB.CH1DATAH) >> 8) & 0xFF;
DMA.CH3.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
DMA.CH3.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
DMA.CH2.REPCNT = 0; //Repeat forever!
DMA.CH2.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm;
DMA.CH2.CTRLB = 0x00; //Hi interrupt on block complete
DMA.CH2.ADDRCTRL = DMA_CH_DESTRELOAD_BURST_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_SRCRELOAD_BLOCK_gc | DMA_CH_SRCDIR_INC_gc; //Dest reloads after each burst, with byte incrementing. Src reloads at end of block, also incrementing address.
DMA.CH2.TRIGSRC = DMA_CH_TRIGSRC_EVSYS_CH2_gc; //Triggered from TCC0 when it hits PER
DMA.CH2.TRFCNT = dacBuf_len;
DMA.CH2.SRCADDR0 = (( (uint16_t) &dacBuf_CH1[0]) >> 0) & 0xFF; //Source address is dacbuf
DMA.CH2.SRCADDR1 = (( (uint16_t) &dacBuf_CH1[0]) >> 8) & 0xFF;
DMA.CH2.SRCADDR2 = 0x00;
DMA.CH2.DESTADDR0 = (( (uint16_t) &DACB.CH0DATAH) >> 0) & 0xFF; //Dest address is high byte of DAC register
DMA.CH2.DESTADDR1 = (( (uint16_t) &DACB.CH0DATAH) >> 8) & 0xFF;
DMA.CH2.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
DMA.CH2.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
//AUX channel (to keep it tx, therefore always rx)
DMA.CH1.CTRLA = 0x00;
DMA.CH1.CTRLA = DMA_CH_RESET_bm;
DMA.CH1.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm; //Do not repeat!
DMA.CH1.CTRLB = 0x00; //No int
DMA.CH1.ADDRCTRL = DMA_CH_SRCDIR_FIXED_gc | DMA_CH_DESTDIR_FIXED_gc; //Source and address fixed.
DMA.CH1.TRIGSRC = DMA_CH_TRIGSRC_USARTC0_RXC_gc;
DMA.CH1.TRFCNT = 0;
DMA.CH1.REPCNT = 0;
DMA.CH1.SRCADDR0 = (( (uint16_t) &dummy) >> 0) & 0xFF;
DMA.CH1.SRCADDR1 = (( (uint16_t) &dummy) >> 8) & 0xFF;
DMA.CH1.SRCADDR2 = 0x00;
DMA.CH1.DESTADDR0 = (( (uint16_t) &USARTC0.DATA) >> 0) & 0xFF;
DMA.CH1.DESTADDR1 = (( (uint16_t) &USARTC0.DATA) >> 8) & 0xFF;
DMA.CH1.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
DMA.CH1.CTRLA |= DMA_CH_REPEAT_bm | DMA_CH_ENABLE_bm; //Enable!
USARTC0.DATA = 0x55;
//Actual data being transferred
DMA.CH0.CTRLA = 0x00;
DMA.CH0.CTRLA = DMA_CH_RESET_bm;
DMA.CH0.CTRLA = DMA_STANDARD_CTRLA;
DMA.CH0.CTRLB = DMA_STANDARD_INTERRUPT;
DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_BURST_gc | DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_DESTRELOAD_BLOCK_gc; //Source reloads after each burst, with byte incrementing. Dest does not reload, but does increment address.
DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_USARTC0_RXC_gc;
DMA.CH0.TRFCNT = DMA_STANDARD_TRANSFER_LENGTH;
DMA.CH0.SRCADDR0 = (( (uint16_t) &USARTC0.DATA) >> 0) & 0xFF; //Source address is ADC
DMA.CH0.SRCADDR1 = (( (uint16_t) &USARTC0.DATA) >> 8) & 0xFF;
DMA.CH0.SRCADDR2 = 0x00;
DMA.CH0.DESTADDR0 = (( (uint16_t) &isoBuf[0]) >> 0) & 0xFF; //Dest address is isoBuf
DMA.CH0.DESTADDR1 = (( (uint16_t) &isoBuf[0]) >> 8) & 0xFF;
DMA.CH0.DESTADDR2 = 0x00;
tiny_calibration_synchronise_phase(500, 200);
median_TRFCNT = 200;
median_TRFCNT_delay = 1; //Wait a few frames before actually setting median_TRFCNT, in case a SOF interrupt was queued during tiny_dma_set_mode_xxx.
//Must enable last for REPCNT won't work!
DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
}
void tiny_dma_loop_mode_3(void){
return;
}
void tiny_dma_set_mode_4(void){
global_mode = 4;
tiny_dma_flush();
//AUX channel (to keep it tx, therefore always rx)
DMA.CH2.CTRLA = 0x00;
DMA.CH2.CTRLA = DMA_CH_RESET_bm;
DMA.CH2.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm; //Do not repeat!
DMA.CH2.CTRLB = 0x00; //No int
DMA.CH2.ADDRCTRL = DMA_CH_SRCDIR_FIXED_gc | DMA_CH_DESTDIR_FIXED_gc; //Source and address fixed.
DMA.CH2.TRIGSRC = DMA_CH_TRIGSRC_USARTC0_RXC_gc;
DMA.CH2.TRFCNT = 0;
DMA.CH2.REPCNT = 0;
DMA.CH2.SRCADDR0 = (( (uint16_t) &dummy) >> 0) & 0xFF;
DMA.CH2.SRCADDR1 = (( (uint16_t) &dummy) >> 8) & 0xFF;
DMA.CH2.SRCADDR2 = 0x00;
DMA.CH2.DESTADDR0 = (( (uint16_t) &USARTC0.DATA) >> 0) & 0xFF;
DMA.CH2.DESTADDR1 = (( (uint16_t) &USARTC0.DATA) >> 8) & 0xFF;
DMA.CH2.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
DMA.CH2.CTRLA |= DMA_CH_REPEAT_bm | DMA_CH_ENABLE_bm; //Enable!
USARTC0.DATA = 0x55;
DMA.CH3.REPCNT = 0; //Repeat forever!
DMA.CH3.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm;
DMA.CH3.CTRLB = 0x00; //No interrupt for DacBuf!!
DMA.CH3.ADDRCTRL = DMA_CH_DESTRELOAD_BURST_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_SRCRELOAD_BLOCK_gc | DMA_CH_SRCDIR_INC_gc; //Dest reloads after each burst, with byte incrementing. Src reloads at end of block, also incrementing address.
DMA.CH3.TRIGSRC = DMA_CH_TRIGSRC_EVSYS_CH1_gc; //Triggered from TCC0 when it hits PER
DMA.CH3.TRFCNT = auxDacBufLen;
DMA.CH3.SRCADDR0 = (( (uint16_t) &dacBuf_CH2[0]) >> 0) & 0xFF; //Source address is dacbuf
DMA.CH3.SRCADDR1 = (( (uint16_t) &dacBuf_CH2[0]) >> 8) & 0xFF;
DMA.CH3.SRCADDR2 = 0x00;
DMA.CH3.DESTADDR0 = (( (uint16_t) &DACB.CH1DATAH) >> 0) & 0xFF; //Dest address is high byte of DAC register
DMA.CH3.DESTADDR1 = (( (uint16_t) &DACB.CH1DATAH) >> 8) & 0xFF;
DMA.CH3.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
DMA.CH3.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
//Actual data being transferred
DMA.CH0.CTRLA = DMA_STANDARD_CTRLA;
DMA.CH0.CTRLB = DMA_STANDARD_INTERRUPT;
DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_BURST_gc | DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_DESTRELOAD_BLOCK_gc; //Source reloads after each burst, with byte incrementing. Dest does not reload, but does increment address.
DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_USARTC0_RXC_gc;
DMA.CH0.TRFCNT = DMA_STANDARD_TRANSFER_LENGTH;
DMA.CH0.SRCADDR0 = (( (uint16_t) &USARTC0.DATA) >> 0) & 0xFF; //Source address is ADC
DMA.CH0.SRCADDR1 = (( (uint16_t) &USARTC0.DATA) >> 8) & 0xFF;
DMA.CH0.SRCADDR2 = 0x00;
DMA.CH0.DESTADDR0 = (( (uint16_t) &isoBuf[0]) >> 0) & 0xFF; //Dest address is isoBuf
DMA.CH0.DESTADDR1 = (( (uint16_t) &isoBuf[0]) >> 8) & 0xFF;
DMA.CH0.DESTADDR2 = 0x00;
DMA.CH1.CTRLA = DMA_STANDARD_CTRLA;
DMA.CH1.CTRLB = DMA_STANDARD_INTERRUPT;
DMA.CH1.ADDRCTRL = DMA_CH_SRCRELOAD_BURST_gc | DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_DESTRELOAD_BLOCK_gc; //Source reloads after each burst, with byte incrementing. Dest does not reload, but does increment address.
DMA.CH1.TRIGSRC = DMA_CH_TRIGSRC_SPIC_gc;
DMA.CH1.TRFCNT = DMA_STANDARD_TRANSFER_LENGTH;
DMA.CH1.SRCADDR0 = (( (uint16_t) &SPIC.DATA) >> 0) & 0xFF; //Source address is ADC
DMA.CH1.SRCADDR1 = (( (uint16_t) &SPIC.DATA) >> 8) & 0xFF;
DMA.CH1.SRCADDR2 = 0x00;
DMA.CH1.DESTADDR0 = (( (uint16_t) &isoBuf[PACKET_SIZE]) >> 0) & 0xFF; //Dest address is isoBuf
DMA.CH1.DESTADDR1 = (( (uint16_t) &isoBuf[PACKET_SIZE]) >> 8) & 0xFF;
DMA.CH1.DESTADDR2 = 0x00;
tiny_calibration_synchronise_phase(500, 200);
median_TRFCNT = 200;
median_TRFCNT_delay = 1; //Wait a few frames before actually setting median_TRFCNT, in case a SOF interrupt was queued during tiny_dma_set_mode_xxx.
DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
DMA.CH1.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
// Hack: manually trigger a transfer to ensure zero phase difference.
DMA.CH0.CTRLA |= DMA_CH_TRFREQ_bm;
}
void tiny_dma_loop_mode_4(void){
return;
}
void tiny_dma_set_mode_5(void){
while(1); //Deliberate Crash! Mode 5 should be invalid.
}
void tiny_dma_set_mode_6(void){
global_mode = 6;
tiny_dma_flush();
DMA.CH2.REPCNT = 0; //Repeat forever!
DMA.CH2.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm;
DMA.CH2.CTRLB = 0x00; //Hi interrupt on block complete
DMA.CH2.ADDRCTRL = DMA_CH_DESTRELOAD_BURST_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_SRCRELOAD_BLOCK_gc | DMA_CH_SRCDIR_INC_gc; //Dest reloads after each burst, with byte incrementing. Src reloads at end of block, also incrementing address.
DMA.CH2.TRIGSRC = DMA_CH_TRIGSRC_EVSYS_CH2_gc; //Triggered from TCC0 when it hits PER
DMA.CH2.TRFCNT = dacBuf_len;
DMA.CH2.SRCADDR0 = (( (uint16_t) &dacBuf_CH1[0]) >> 0) & 0xFF; //Source address is dacbuf
DMA.CH2.SRCADDR1 = (( (uint16_t) &dacBuf_CH1[0]) >> 8) & 0xFF;
DMA.CH2.SRCADDR2 = 0x00;
DMA.CH2.DESTADDR0 = (( (uint16_t) &DACB.CH0DATAH) >> 0) & 0xFF; //Dest address is high byte of DAC register
DMA.CH2.DESTADDR1 = (( (uint16_t) &DACB.CH0DATAH) >> 8) & 0xFF;
DMA.CH2.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
DMA.CH2.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
DMA.CH3.REPCNT = 0; //Repeat forever!
DMA.CH3.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm;
DMA.CH3.CTRLB = 0x00; //No interrupt for DacBuf!!
DMA.CH3.ADDRCTRL = DMA_CH_DESTRELOAD_BURST_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_SRCRELOAD_BLOCK_gc | DMA_CH_SRCDIR_INC_gc; //Dest reloads after each burst, with byte incrementing. Src reloads at end of block, also incrementing address.
DMA.CH3.TRIGSRC = DMA_CH_TRIGSRC_EVSYS_CH1_gc; //Triggered from TCC0 when it hits PER
DMA.CH3.TRFCNT = auxDacBufLen;
DMA.CH3.SRCADDR0 = (( (uint16_t) &dacBuf_CH2[0]) >> 0) & 0xFF; //Source address is dacbuf
DMA.CH3.SRCADDR1 = (( (uint16_t) &dacBuf_CH2[0]) >> 8) & 0xFF;
DMA.CH3.SRCADDR2 = 0x00;
DMA.CH3.DESTADDR0 = (( (uint16_t) &DACB.CH1DATAH) >> 0) & 0xFF; //Dest address is high byte of DAC register
DMA.CH3.DESTADDR1 = (( (uint16_t) &DACB.CH1DATAH) >> 8) & 0xFF;
DMA.CH3.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
DMA.CH3.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
DMA.CH0.CTRLA = 0x00;
DMA.CH0.CTRLA = DMA_CH_RESET_bm;
DMA.CH0.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm;
DMA.CH0.CTRLB = 0x00; //No interrupt!
DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_BURST_gc | DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_DESTRELOAD_BLOCK_gc; //Source reloads after each burst, with byte incrementing. Dest does not reload, but does increment address.
DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_ADCA_CH0_gc; //Triggered from ADCA channel 0
DMA.CH0.TRFCNT = BUFFER_SIZE;
DMA.CH0.SRCADDR0 = (( (uint16_t) &ADCA.CH0.RESL) >> 0) & 0xFF; //Source address is ADC
DMA.CH0.SRCADDR1 = (( (uint16_t) &ADCA.CH0.RESL) >> 8) & 0xFF;
DMA.CH0.SRCADDR2 = 0x00;
DMA.CH0.DESTADDR0 = (( (uint16_t) &isoBuf[0]) >> 0) & 0xFF; //Dest address is isoBuf
DMA.CH0.DESTADDR1 = (( (uint16_t) &isoBuf[0]) >> 8) & 0xFF;
DMA.CH0.DESTADDR2 = 0x00;
tiny_calibration_synchronise_phase(500, 200);
median_TRFCNT = 400;
median_TRFCNT_delay = 1; //Wait a few frames before actually setting median_TRFCNT, in case a SOF interrupt was queued during tiny_dma_set_mode_xxx.
DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
}
void tiny_dma_loop_mode_6(void){
return;
}
void tiny_dma_set_mode_7(void){
global_mode = 7;
tiny_dma_flush();
DMA.CH2.REPCNT = 0; //Repeat forever!
DMA.CH2.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm;
DMA.CH2.CTRLB = 0x00; //Hi interrupt on block complete
DMA.CH2.ADDRCTRL = DMA_CH_DESTRELOAD_BURST_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_SRCRELOAD_BLOCK_gc | DMA_CH_SRCDIR_INC_gc; //Dest reloads after each burst, with byte incrementing. Src reloads at end of block, also incrementing address.
DMA.CH2.TRIGSRC = DMA_CH_TRIGSRC_EVSYS_CH2_gc; //Triggered from TCC0 when it hits PER
DMA.CH2.TRFCNT = dacBuf_len;
DMA.CH2.SRCADDR0 = (( (uint16_t) &dacBuf_CH1[0]) >> 0) & 0xFF; //Source address is dacbuf
DMA.CH2.SRCADDR1 = (( (uint16_t) &dacBuf_CH1[0]) >> 8) & 0xFF;
DMA.CH2.SRCADDR2 = 0x00;
DMA.CH2.DESTADDR0 = (( (uint16_t) &DACB.CH0DATAH) >> 0) & 0xFF; //Dest address is high byte of DAC register
DMA.CH2.DESTADDR1 = (( (uint16_t) &DACB.CH0DATAH) >> 8) & 0xFF;
DMA.CH2.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
DMA.CH2.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
DMA.CH3.REPCNT = 0; //Repeat forever!
DMA.CH3.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm;
DMA.CH3.CTRLB = 0x00; //No interrupt for DacBuf!!
DMA.CH3.ADDRCTRL = DMA_CH_DESTRELOAD_BURST_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_SRCRELOAD_BLOCK_gc | DMA_CH_SRCDIR_INC_gc; //Dest reloads after each burst, with byte incrementing. Src reloads at end of block, also incrementing address.
DMA.CH3.TRIGSRC = DMA_CH_TRIGSRC_EVSYS_CH1_gc; //Triggered from TCC0 when it hits PER
DMA.CH3.TRFCNT = auxDacBufLen;
DMA.CH3.SRCADDR0 = (( (uint16_t) &dacBuf_CH2[0]) >> 0) & 0xFF; //Source address is dacbuf
DMA.CH3.SRCADDR1 = (( (uint16_t) &dacBuf_CH2[0]) >> 8) & 0xFF;
DMA.CH3.SRCADDR2 = 0x00;
DMA.CH3.DESTADDR0 = (( (uint16_t) &DACB.CH1DATAH) >> 0) & 0xFF; //Dest address is high byte of DAC register
DMA.CH3.DESTADDR1 = (( (uint16_t) &DACB.CH1DATAH) >> 8) & 0xFF;
DMA.CH3.DESTADDR2 = 0x00;
//Must enable last for REPCNT won't work!
DMA.CH3.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
DMA.CH0.CTRLA = 0x00;
DMA.CH0.CTRLA = DMA_CH_RESET_bm;
DMA.CH0.CTRLA = DMA_CH_BURSTLEN_2BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm; //Do not repeat!
DMA.CH0.CTRLB = 0x00; //No interrupt!
DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_BURST_gc | DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTDIR_INC_gc | DMA_CH_DESTRELOAD_BLOCK_gc; //Source reloads after each burst, with byte incrementing. Dest does not reload, but does increment address.
DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_ADCA_CH0_gc; //Triggered from ADCA channel 0
DMA.CH0.TRFCNT = BUFFER_SIZE;
DMA.CH0.SRCADDR0 = (( (uint16_t) &ADCA.CH0.RESL) >> 0) & 0xFF; //Source address is ADC
DMA.CH0.SRCADDR1 = (( (uint16_t) &ADCA.CH0.RESL) >> 8) & 0xFF;
DMA.CH0.SRCADDR2 = 0x00;
DMA.CH0.DESTADDR0 = (( (uint16_t) &isoBuf[0]) >> 0) & 0xFF; //Dest address is isoBuf
DMA.CH0.DESTADDR1 = (( (uint16_t) &isoBuf[0]) >> 8) & 0xFF;
DMA.CH0.DESTADDR2 = 0x00;
tiny_calibration_synchronise_phase(500, 200);
median_TRFCNT = 400;
median_TRFCNT_delay = 1; //Wait a few frames before actually setting median_TRFCNT, in case a SOF interrupt was queued during tiny_dma_set_mode_xxx.
DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm; //Enable!
}
void tiny_dma_loop_mode_7(void){
}
ISR(DMA_CH0_vect){
DMA.INTFLAGS = 0x01;
//dma_ch0_ran++;
//uds.dma_ch0_cntL = dma_ch0_ran & 0xff;
//uds.dma_ch0_cntH = (dma_ch0_ran >> 8) & 0xff;
#ifdef SINGLE_ENDPOINT_INTERFACE
DMA.CH0.CTRLA = 0x00;
DMA.CH0.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm; //Do not repeat!
DMA.CH0.TRFCNT = HALFPACKET_SIZE;
short ptr = usb_state ? 0 : PACKET_SIZE;
DMA.CH0.DESTADDR0 = (( (uint16_t) &isoBuf[ptr]) >> 0) & 0xFF; //Dest address is isoBuf
DMA.CH0.DESTADDR1 = (( (uint16_t) &isoBuf[ptr]) >> 8) & 0xFF;
DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm;
#endif
}
ISR(DMA_CH1_vect){
DMA.INTFLAGS = 0x02;
//dma_ch1_ran++;
//uds.dma_ch1_cntL = dma_ch1_ran & 0xff;
//uds.dma_ch1_cntH = (dma_ch1_ran >> 8) & 0xff;
#ifdef SINGLE_ENDPOINT_INTERFACE
DMA.CH1.CTRLA = 0x00;
DMA.CH1.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm; //Do not repeat!
DMA.CH1.TRFCNT = HALFPACKET_SIZE;
short ptr = usb_state ? HALFPACKET_SIZE : PACKET_SIZE + HALFPACKET_SIZE;
DMA.CH1.DESTADDR0 = (( (uint16_t) &isoBuf[ptr]) >> 0) & 0xFF; //Dest address is isoBuf
DMA.CH1.DESTADDR1 = (( (uint16_t) &isoBuf[ptr]) >> 8) & 0xFF;
DMA.CH1.CTRLA |= DMA_CH_ENABLE_bm;
#endif
}