I'm working on a project where I need to poll four encoders (CUI AMT212B) over half-duplex RS-485 UART at 10kHz, while also performing other CPU intensive tasks.
To poll each encoder I need to send a one byte command, and then receive a 2-byte response. My plan is to configure the DMA channels of the Teensy so that one channel triggers off the PIT timer to write the command to the send FIFO buffer, and then configure another DMA channel to read the two-byte response from the receive FIFO buffer back into memory; all without CPU intervention. I have this working well between two ports of the Teensy itself, with one port simulating the encoder.
Where I am having trouble is configuring the LPUART peripheral to trigger the transmit pin of my RS-485 transceiver. The reference manual suggests that this is possible by configuring the RTS_B pin of the corresponding pin, but I haven't been able to figure out which physical pins on the Teensy are the RTS_B pins for each serial port. Is what I am describing possible, or am I missing something?
Here's the code I have so far. It parses a 16-bit integer from the Serial monitor, then writes that integer to the transmit FIFO of Serial2, which is connected to Serial1. Serial1 is configured such that when its recieve FIFO has 2 bytes, it triggers a DMA transfer to memory. Since I'm not really using the HarwareSerial API, I don't expect the transmitterEnable call to work, but I do expect setting the 1st bit of LPUART4_MODIR to cause some pin somewhere to assert while LPUART4 (Serial2) is transmitting. I just can't seem to find that pin.
To poll each encoder I need to send a one byte command, and then receive a 2-byte response. My plan is to configure the DMA channels of the Teensy so that one channel triggers off the PIT timer to write the command to the send FIFO buffer, and then configure another DMA channel to read the two-byte response from the receive FIFO buffer back into memory; all without CPU intervention. I have this working well between two ports of the Teensy itself, with one port simulating the encoder.
Where I am having trouble is configuring the LPUART peripheral to trigger the transmit pin of my RS-485 transceiver. The reference manual suggests that this is possible by configuring the RTS_B pin of the corresponding pin, but I haven't been able to figure out which physical pins on the Teensy are the RTS_B pins for each serial port. Is what I am describing possible, or am I missing something?
Here's the code I have so far. It parses a 16-bit integer from the Serial monitor, then writes that integer to the transmit FIFO of Serial2, which is connected to Serial1. Serial1 is configured such that when its recieve FIFO has 2 bytes, it triggers a DMA transfer to memory. Since I'm not really using the HarwareSerial API, I don't expect the transmitterEnable call to work, but I do expect setting the 1st bit of LPUART4_MODIR to cause some pin somewhere to assert while LPUART4 (Serial2) is transmitting. I just can't seem to find that pin.
Code:
#include "imxrt.h"
#include "DMAChannel.h"
#define LPUART6 Serial1
#define LPUART4 Serial2
volatile uint16_t recieve = 0;
uint16_t last = 0;
uint16_t new_send = 0;
DMAChannel dma;
void setup() {
// Configure DMA channel that triggers the encoder reading
Serial.begin(9600);
LPUART6.begin(9600);
LPUART4.begin(9600);
LPUART4.transmitterEnable(9);
Serial.print("Config dma0....");
DMA_TCD0_SADDR = &LPUART6_DATA; // Source address
DMA_TCD0_SOFF = 0; // Adjustment to the source address made after every minor loop iteration
DMA_TCD0_ATTR = (0b000000 << 11) | (0b000 << 8) | (0b000000 << 3) | (0b000); // SMOD | SSIZE | DMOD | DSIZE
DMA_TCD0_NBYTES = 2; // Set number of bytes to transfer per minor loop iteration
DMA_TCD0_SLAST = 0; // Source address adjustment after major loop completion
DMA_TCD0_DADDR = &recieve; // Destination address
DMA_TCD0_DOFF = 1;
DMA_TCD0_DLASTSGA = -2;
DMA_TCD0_CSR = (0b00 << 14) | (0b00000 << 8) | (0b0 << 5) | (0b0 << 4) | (0b0 << 3) | (0b0 << 2); // BWC | MAJORLINKCH | ESG | DREQ | INTHALF | INTMAJOR
DMA_TCD0_BITER = (0b0 << 15) | 1; // Channel linking disabled | single service request (NO major looping)
DMA_TCD0_CITER = DMA_TCD0_BITER; // CITER and BITER must be the same when the TCD memory is loaded by software. CITER will decrement with each minor loop
DMAMUX_CHCFG0 = (0b1 << 31) | (0b0 << 30) | (0b0 << 29) | DMAMUX_SOURCE_LPUART6_RX; // Enable DMA mux | enable periodic trigger | disable always on | set hardware trigger source
LPUART6_BAUD |= 1 << 21; // enables DMA request generation when RX FIFO buffer contains n > watermark bytes
LPUART6_WATER = 0b1 << 16; // set RX watermark to 1 (fires DMA request when there are >1 bytes in the RX FIFO )
LPUART4_MODIR |= 0b1 << 1;
DMA_SERQ = 0;
Serial.println("Done.");
Serial.setTimeout(50);
}
void loop() {
if (Serial.available()) {
new_send = (uint16_t) Serial.parseInt();
if (new_send != 0) {
Serial.println();
Serial.print("Serial2 sending: ");
Serial.println(new_send);
LPUART4_DATA = (0x00FF & new_send);
LPUART4_DATA = ((0xFF00 & new_send) >> 8);
}
}
if (recieve != last) {
last = recieve;
Serial.println();
Serial.print("Serial1 recieved: ");
Serial.println(recieve);
}
}