I'm working on a DMA-based AX-12 servo driver. This implements a half-duplex async interface to the servos.
I've gotten the TX side working. Well, almost. when I look at the data stream with a o-scope I can see that the second byte of the Tx buffer is not being sent. Transmission goes straight from the 1st byte to the 3rd byte.
I suspect the uart's fifo's are immediately requesting the 2nd byte, it's supplied by the eDMA, but the uart is not seeing it. I'm thinking of just manually pushing data to the uart until it says it doesn't need anymore right now, and then DMA'ing the rest.
Any thoughts? Thanks in advance!
I've gotten the TX side working. Well, almost. when I look at the data stream with a o-scope I can see that the second byte of the Tx buffer is not being sent. Transmission goes straight from the 1st byte to the 3rd byte.
I suspect the uart's fifo's are immediately requesting the 2nd byte, it's supplied by the eDMA, but the uart is not seeing it. I'm thinking of just manually pushing data to the uart until it says it doesn't need anymore right now, and then DMA'ing the rest.
Any thoughts? Thanks in advance!
Code:
//*****************************************************************************
// Changes I had to make:
// 1) I had to remove the like-named routine from Serial3 !!!
// void uart2_status_isr(void) {
//*****************************************************************************
#include <kinetis.h>
enum {
cPin_OnTeensyLed = 13,
cPin_TxDriveEnable = 24,
cPin_RxDriveEnable = 25,
cPin_UartTx = 8,
cPin_UartRx = 7
};
#define cBaudRate 10000
#define cIRQ_PRIORITY 64
int volatile transmitting;
uint32_t volatile mDmaErr;
int volatile mTxCycleCompleted;
uint32_t mLedTimer;
char cMessage [] = "\x3C\xFF\xF0\xFF\x00\xFF\xFF\xFF\xFF\xFF\x00\xFF\x00\xFF\x00\xFF\x00";
//*****************************************************************************
void dma_ch10_isr(void) {
mDmaErr |= DMA_ES;
DMA_CINT = DMA_CINT_CINT(10); // Clear interrupt
UART2_C5 = 0; // Clear C5[TDMAS]
UART2_C2 = UART_C2_TE | UART_C2_TCIE; // | UART_C2_TIE;
}
//*****************************************************************************
void uart2_status_isr(void) {
if (UART2_S1 & UART_S1_TC) {
transmitting = 0; // Report our completion; // TODO: Make better!
mTxCycleCompleted = 1;
digitalWrite(cPin_TxDriveEnable, HIGH);
UART2_C2 = UART_C2_TE;
}
}
//*****************************************************************************
void startTx(void * iTxAddress, uint32_t iTxLength) {
DMAMUX0_CHCFG10 = 0;
DMA_CERQ = DMA_CERQ_CERQ(10);
digitalWrite(cPin_TxDriveEnable, LOW);
transmitting = 1;
DMA_TCD10_CITER_ELINKNO =
DMA_TCD10_BITER_ELINKNO = iTxLength; // BITER & CITER, which must match!
DMA_TCD10_NBYTES_MLNO = DMA_TCD_NBYTES_SMLOE | // Minor Loop Offset --> Src ENABLED
// Minor Loop Offset --> Dest DISABLED
DMA_TCD_NBYTES_MLOFFYES_MLOFF(1) | // Increment Src addr by 1
DMA_TCD_NBYTES_MLOFFYES_NBYTES(1); // One byte at a time!
DMA_TCD10_SADDR = iTxAddress; // TCD Source Addr
DMA_TCD10_SOFF = 0L; // TCD Signed Source Address Offset
DMA_TCD10_ATTR = 0L; // TCD Transfer Attributes
DMA_TCD10_SLAST = 0L; // TCD Last Source Addr Adj.
DMA_TCD10_DADDR = &UART2_D; // TCD Destination Address
DMA_TCD10_DOFF = 0L; // TCD Signed Dest Address Offset
DMA_TCD10_DLASTSGA = 0L; // TCD Last Destination Addr Adj
DMA_SERQ = DMA_SERQ_SERQ(10);
DMA_SERQ = DMA_SERQ_SERQ(10);
DMAMUX0_CHCFG10 = DMAMUX_ENABLE | DMAMUX_SOURCE_UART2_TX;
UART2_C5 = UART_C5_TDMAS | UART_C5_RDMAS; // DMA enablements
UART2_C2 = UART_C2_TE | UART_C2_TIE; // Tx enabled, IEs (interrupts) needed for DMA
DMA_TCD10_CSR = DMA_TCD_CSR_INTMAJOR;
DMA_TCD10_CSR = (DMA_TCD_CSR_INTMAJOR | DMA_TCD_CSR_START);
}
//*****************************************************************************
void setupUartAndDma() {
SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
SIM_SCGC7 |= SIM_SCGC7_DMA;
// We're assuming our TCD is inactive!
DMAMUX0_CHCFG10 = 0; // Tx
DMAMUX0_CHCFG11 = 0; // Rx
DMA_CR = DMA_CR_EMLM | DMA_CR_ERCA;
DMA_CERQ = DMA_CERQ_CERQ(10);
DMA_CEEI = DMA_CEEI_CEEI(10);
DMA_CINT = DMA_CINT_CINT(10);
if (DMA_ERR & DMA_ERR_ERR10) {
DMA_CERR |= DMA_CERR_CERR(10);
}
transmitting = 0;
SIM_SCGC4 |= SIM_SCGC4_UART2;
UART2_C2 = 0; // ONLY after clock is on! Don't ask me how I know...
CORE_PIN7_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); // Rx
CORE_PIN8_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); // Tx
uint32_t divisor = (((F_BUS * 2) + ((cBaudRate) >> 1)) / (cBaudRate));
UART2_BDH = (divisor >> 13) & 0x1F;
UART2_BDL = (divisor >> 5) & 0xFF;
UART2_C4 = divisor & 0x1F;
UART2_C1 = 0;
UART2_S2 &= ~0x10; // No Rx invert
UART2_C3 &= ~0x10; // No Tx invert
UART2_PFIFO = 0;
NVIC_SET_PRIORITY(IRQ_DMA_CH10, cIRQ_PRIORITY);
NVIC_ENABLE_IRQ(IRQ_DMA_CH10);
NVIC_SET_PRIORITY(IRQ_UART2_STATUS, cIRQ_PRIORITY);
NVIC_ENABLE_IRQ(IRQ_UART2_STATUS);
}
//*****************************************************************************
void setup() {
mDmaErr = 0L;
mTxCycleCompleted = 0L;
mLedTimer = 0;
pinMode(cPin_OnTeensyLed, OUTPUT);
digitalWrite(cPin_OnTeensyLed, LOW);
pinMode(cPin_TxDriveEnable, OUTPUT);
pinMode(cPin_RxDriveEnable, OUTPUT);
setupUartAndDma();
}
//*****************************************************************************
void loop() {
if ( ! transmitting) {
delay(20);
startTx(cMessage, 17);
}
}