I'm using an XMega32A4U as a USB Mass Storage device. I got the whole thing functional, and it interoperates properly, but in doing so, I've had to do some things that give me pause.
What I really wanted to do is set up two DMA channels to make a disk block's worth of cipher material. So the idea is that channel 1 loads the STATE register, and then the completion ISR hits the AES START bit. Channel 0 is triggered by AES and copies the STATE register out to a buffer. The ISR for channel 0 checks for completion, alters the iv buffer according to the algorithm and then manually triggers channel 1.
What's happening is that when I hit the AES start bit in the channel 1 ISR is that the AES ERROR bit turns on and that's all she wrote.
// Set up DMA channel 0 to do 16 byte blocks from AES // to our pre_ct, advancing forward every time. DMA.CH0.CTRLA &= ~(DMA_CH_ENABLE_bm); DMA.CH0.CTRLA |= DMA_CH_RESET_bm; DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm; //DMA.CH0.CTRLA = 0; DMA.CH0.CTRLB |= DMA_CH_TRNINTLVL_MED_gc; // lower than USB, higher than background DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_AES_gc; DMA.CH0.TRFCNTL = BLOCKSIZE; DMA.CH0.TRFCNTH = 0; // Going from a single address to a constantly moving forward buffer every time DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_NONE_gc | DMA_CH_SRCDIR_FIXED_gc | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_INC_gc; DMA.CH0.REPCNT = 0; // Going from the AES state register to our pre_ct buffer DMA.CH0.SRCADDR0 = (uint8_t)((uint16_t)&AES.STATE >> 0); DMA.CH0.SRCADDR1 = (uint8_t)((uint16_t)&AES.STATE >> 8); DMA.CH0.SRCADDR2 = 0; DMA.CH0.DESTADDR0 = (uint8_t)(((uint16_t)pre_ct) >> 0); DMA.CH0.DESTADDR1 = (uint8_t)(((uint16_t)pre_ct) >> 8); DMA.CH0.DESTADDR2 = 0; // Set up DMA channel 1 to do 16 bytes from the nonce buffer to AES, // repeating the same thing every time. DMA.CH1.CTRLA &= ~(DMA_CH_ENABLE_bm); DMA.CH1.CTRLA |= DMA_CH_RESET_bm; DMA.CH1.CTRLA |= DMA_CH_ENABLE_bm; //DMA.CH1.CTRLA = 0; DMA.CH1.CTRLB |= DMA_CH_TRNINTLVL_MED_gc; // lower than USB, higher than background DMA.CH1.TRIGSRC = DMA_CH_TRIGSRC_OFF_gc; DMA.CH1.TRFCNTL = BLOCKSIZE; DMA.CH1.TRFCNTH = 0; // Going from the same buffer every time to just a single address DMA.CH1.ADDRCTRL = DMA_CH_SRCRELOAD_BLOCK_gc | DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_FIXED_gc; DMA.CH1.REPCNT = 0; // Going from our nonce buffer to the AES state register DMA.CH1.SRCADDR0 = (uint8_t)(((uint16_t)nonce) >> 0); DMA.CH1.SRCADDR1 = (uint8_t)(((uint16_t)nonce) >> 8); DMA.CH1.SRCADDR2 = 0; DMA.CH1.DESTADDR0 = (uint8_t)((uint16_t)&AES.STATE >> 0); DMA.CH1.DESTADDR1 = (uint8_t)((uint16_t)&AES.STATE >> 8); DMA.CH1.DESTADDR2 = 0; // And go! //DMA.CH1.CTRLA |= DMA_CH_ENABLE_bm; DMA.CH1.CTRLA |= DMA_CH_TRFREQ_bm;
In the meantime, I've foregone DMA and am just using a for() loop to copy the state material in and out in an AES ISR. That's working, sort of, but brings me to my other concern - it seems like I have to load the key every time or it gets corrupted. Can't the AES system just keep reusing the key? If I have to reload the key every time, then that's going to be a third DMA channel just to do that. No me gusta.