@Paul and all,
As Half duplex keeps coming up in different topics, I thought about migrating the half duplex support I did in another Pull request that had additional stuff, much of which was already merged in...
So I have created a new branch:
https://github.com/KurtE/cores/tree/serial_half_duplex
Which I think I migrated the half duplex support in from that other PR, which I will close out.
The idea is to add a new format to the format defines for SerialX.begin
Something like: Serial1.begin(1000000, SERIAL_HALF_DUPLEX);
And it takes care of changing the the right register to allow half duplex, plus sets up that when you do a TX it switches to TX mode and when the ISR comes in saying we have no more to transmit it switches back to RX mode.
For T3.x it is pretty clean as I do the setup in begin and sets up the same variables used by transmitterEnable to set or clear the GPIO pin, but in this case the register and mask are setup for the bitband address of the correct bit of the register that controls the direction... So no changes to the TX or ISR needed.
For T4.x not as easy, as we don't have bitband. Instead the transmitterEnable code uses the two different registers that Set or Clear bits in the Port register associated with the pin. Unfortunately we don't have set and clear on the Uarts CTRL register so have to set or clear that bit manually...
Note: without these types of changes, what I have done in the past in some libraries like my Dynamixel Library (bioloidSerial) is to something like:
Code:
#if defined(KINETISK) || defined (KINETISL)
static KINETISK_UART_t *s_pkuart = nullptr;
void dxlInit(long baud, HardwareSerial* pserial, int direction_pin, int tx_pin, int rx_pin ) {
// Need to enable the PU resistor on the TX pin
s_paxStream = pserial;
s_direction_pin = direction_pin; // save away.
if (pserial == &Serial1) s_pkuart = &KINETISK_UART0;
else if (pserial == &Serial2) s_pkuart = &KINETISK_UART1;
else if (pserial == &Serial3) s_pkuart = &KINETISK_UART2;
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
else if (pserial == &Serial4) s_pkuart = &KINETISK_UART3;
else if (pserial == &Serial5) s_pkuart = &KINETISK_UART4;
#endif
...
Which again can be made to work. But it also has an unintended consequence. That is the current versions of Teensyduino are developed, such that if you don't use a SerialX object, then that object is not create, nor any of the other data structures associated with it, like RX and TX Buffers.
But this code references all of them, even though only one of them will actually be used... But all are now included in the Sketch...
The #else for the T4.xs is similar but different actual registers and structure...
For the fun of it, I started playing with a test sketch to see if I can avoid bringing in all of the Serial objects, starting off with T4.x... All of the data needed is actually stored to do this is contained within the SerialX object... And it is more complex than T3.x as we may need to also setup the Hardware Input Select register, depending on the pin...
I have done a similar hack before for SPI, but that was easier as it is a base class currently with no Vtable so I know the first entry is the pointer to the LPSPI object and the next is a pointer to our Hardware Structure.
But Serial is a sub-class of Stream which is a sub-class of Print... So playing around to figure out where it is... Have a sketch that properly can now print out some of the information...
Code:
extern void printSerData(HardwareSerial *pserial);
uint8_t index_imxrt_lpuart = -1;
void setup() {
while (!Serial) ;
Serial.begin(115200);
Serial1.begin(115200);
delay(50);
uint32_t *pserial = (uint32_t*)&Serial1;
Serial.printf("PS:%x PU:%x PH:xx\n", &Serial1,
(uint32_t*)&IMXRT_LPUART6/*, &UART6_Hardware*/);
for (uint8_t i = 0; i < 10; i++) {
Serial.printf("%d:%x\n", i, pserial[i]);
if ((pserial[i] >= (uint32_t)&IMXRT_LPUART1) && (pserial[i] <= (uint32_t)&IMXRT_LPUART8)) {
index_imxrt_lpuart = i;
Serial.println(" imxrt_lpuart index");
}
}
printSerData(& Serial1);
printSerData(& Serial2);
printSerData(& Serial3);
printSerData(& Serial4);
printSerData(& Serial8);
}
void printSerData(HardwareSerial *pserial) {
pserial->begin(115200); // make sure we have access.
uint32_t *p32 = (uint32_t *)pserial;
IMXRT_LPUART_t *port = (IMXRT_LPUART_t*)p32[index_imxrt_lpuart];
HardwareSerial::hardware_t * phard = (HardwareSerial::hardware_t *)p32[index_imxrt_lpuart + 1];
Serial.println("---------------------------------------------------------------");
Serial.printf("%x %x %x\n", (uint32_t*)pserial, (uint32_t)port, (uint32_t)phard);
Serial.flush();
Serial.printf(" B:%x ST:%x CT: %x\n", port->BAUD, port->STAT, port->CTRL);
Serial.flush( );
Serial.printf(" I:%d P:%d %x %x\n", phard->serial_index, phard->tx_pins[0].pin,
(uint32_t)phard->tx_pins[0].select_input_register, phard->tx_pins[0].select_val);
Serial.flush();
}
void loop() {
}
Output from sketch:
Code:
PS:200007fc PU:40198000 PH:xx
0:20000124
1:0
2:3e8
3:0
4:40198000
imxrt_lpuart index
5:20000140
6:0
7:200017b8
8:200017f8
9:0
---------------------------------------------------------------
200007fc 40198000 20000140
B:19000008 ST:c00000 CT: 3c0000
I:0 P:1 401f8554 0
---------------------------------------------------------------
200008c0 40190000 2000085c
B:19000008 ST:800000 CT: 3c0000
I:1 P:8 401f8544 2
---------------------------------------------------------------
20000920 40188000 20000980
B:19000008 ST:800000 CT: 3c0000
I:2 P:14 401f8530 1
---------------------------------------------------------------
20000a48 4018c000 200009e4
B:19000008 ST:800000 CT: 3c0000
I:3 P:17 401f853c 0
---------------------------------------------------------------
20000b0c 40194000 20000aa8
B:19000008 ST:c00000 CT: 3c0000
I:7 P:35 401f854c 1
One might call this a little bit of a hack
:0
As for T3.x/LC - not so simple as our Serial objects are not controlled by structures like this. They all have their own code with hard coded registers... So not sure how I would hack this one and remove the look at the Serial pointer and have my own table to drive it....
But now to testing some of the above new branch, and then maybe do a PR...