Hi sorry to bump this thread.
I have joined the forum as am interested in implementing some Lin communication on an ESP to control some ambient light lin devices on my car and I have found this thread to very interesting.
Phatpaul, I was wondering if you are sharing your LIn driver including the headers. It seems to me something very complex for my skills level and it would be a great starting point to have a working driver as an start point.
Will it work as well in an ESP8266?
Thanks a lot in advance
Best regards
UART break at first
Re: UART break at first
Well, a recent update to esp-idf has broken my LIN break method. In 3.3.5 it works, then in 3.3.6, the break is not long enough.
From the release notes:
https://github.com/espressif/esp-idf/re ... tag/v3.3.6
Perhaps something in one of these changes broke my LIN solution:
Freemodbus: Fixed rs485 rts de-assert fail when tx delayed (#6728)
Freemodbus: Added the MB_PORT_TASK_AFFINITY kconfig option for modbus tasks (#6700)
UART: Fixed uart module reset issue (#1202)
UART: Added config to support placing UART ISR in IRAM
UART: Fixed a typo in the error message of invalid rx_thresh_xoff
@Bencium I can share my example project, but I'll need a little time to prepare it. Do you need LIN master or slave for your application? If the lights you want to control are already commanded by a master (i.e. part of your car) then I'm not sure how you can override that.
From the release notes:
https://github.com/espressif/esp-idf/re ... tag/v3.3.6
Perhaps something in one of these changes broke my LIN solution:
Freemodbus: Fixed rs485 rts de-assert fail when tx delayed (#6728)
Freemodbus: Added the MB_PORT_TASK_AFFINITY kconfig option for modbus tasks (#6700)
UART: Fixed uart module reset issue (#1202)
UART: Added config to support placing UART ISR in IRAM
UART: Fixed a typo in the error message of invalid rx_thresh_xoff
@Bencium I can share my example project, but I'll need a little time to prepare it. Do you need LIN master or slave for your application? If the lights you want to control are already commanded by a master (i.e. part of your car) then I'm not sure how you can override that.
Re: UART break at first
Hi I had the same problem and "fixed" it. After lots of trial and error I added a second wait_for_tx_done after the first one. And now it "works" again for some reason. I am not happy with the solution, but after spending two days to understand how to add a brake at-front into the library I gave up. The break-at-end is so complicated embedded that I can not get it to send the break before the data....
Best regards and I hope the quick fix fix helps. I wish I could understand the UART code better and contribute something with more value.
Best regards and I hope the quick fix fix helps. I wish I could understand the UART code better and contribute something with more value.
Re: UART break at first
@FlorianR thanks! You saved me a bunch of time. (I had just reverted to 3.3.5 until I had time to bisect the problem.)
I also don't know why this works, but since this whole break-at-first method is a hack anyway, your solution fits perfectly.
To be clear, here's the modified
I also don't know why this works, but since this whole break-at-first method is a hack anyway, your solution fits perfectly.
To be clear, here's the modified
Code: Select all
void LIN_driver_start_frame(uint8_t pid)
{
uint32_t baudrate;
uint8_t master_tx_buf[2];
master_tx_buf[0] = 0x55; // sync byte
master_tx_buf[1] = pid;
uint8_t dummy = 0;
uart_flush_input(lin_uart_num); // since we are the master, clear out rx buff before starting a frame
xQueueReset(lin_uart_event_queue); // clear the q for slave rx uart breaks
/* Send break character */
// this method sucks b/c it must send a dummy char before the break
// Note: if use this, then +1 to LIN_IN_HEADER_SIZE for dummy byte.
//uart_write_bytes_with_break(lin_uart_num, (char *)&dummy, 1, LIN_BREAK_LEN);
// this method really sucks because of a blocking delay!
//uart_set_line_inverse(param_ptr_config->uart_port_num, UART_INVERSE_TXD);
//ets_delay_us(677);
//uart_set_line_inverse(param_ptr_config->uart_port_num, UART_INVERSE_DISABLE);
//uart_hal_tx_break(&(uart_context[uart_num].hal), 0); - not available in IDF 3x
// Temporarily change baudrate to slightly lower and send a 0 byte
// to get the right baudrate, we want 9 bits (1 start + 8 data) to take the time of 13 bits (one break)
uart_get_baudrate(lin_uart_num, &baudrate);
#define LIN_BREAK_BAUDRATE(BAUD) ((BAUD * 9) / 13)
uart_set_baudrate(lin_uart_num, LIN_BREAK_BAUDRATE(baudrate));
uart_write_bytes(lin_uart_num, (char *)&dummy, 1); // send a zero byte. This call must be blocking.
uart_wait_tx_done(lin_uart_num, 2); // shouldn't be necessary??
uart_wait_tx_done(lin_uart_num, 2); // add 2nd uart_wait_tx_done per https://esp32.com/viewtopic.php?p=98456#p98456
uart_set_baudrate(lin_uart_num, baudrate); // set baudrate back to normal after break is sent
// we have to fake a break detect for the slave, since it doesn't detect it with this method.
uart_event_t event = {.type = UART_BREAK};
xQueueSend(lin_uart_event_queue, (void *)&event, 0);
// Now send the sync and PID bytes
uart_write_bytes(lin_uart_num, (char *)master_tx_buf, sizeof(master_tx_buf));
}
Re: UART break at first
I now added it to uart.h/.c itself. Also on git https://github.com/espressif/esp-idf/pull/10827
Hello I have a solid working function for that now:
uart.h:
uart.c:
Hello I have a solid working function for that now:
uart.h:
Code: Select all
int uart_write_bytes_with_break(uart_port_t uart_num, const void* src, size_t size, int brk_len);
/**
* @brief Send a break signal on the UART TX line without sending any data bytes.
*
* This function waits until the TX line is idle (all previously queued/buffered data
* has been transmitted), then sends a break signal of the given duration.
* It does not return until the break signal has been sent out.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param brk_len break signal duration(unit: the time it takes to send one bit at current baudrate)
*
* @return
* - (-1) Parameter error
* - (0) Break signal sent successfully
*/
int uart_write_break(uart_port_t uart_num, int brk_len);uart.c:
Code: Select all
int uart_write_break(uart_port_t uart_num, int brk_len)
{
ESP_RETURN_ON_FALSE((uart_num < UART_NUM_MAX), (-1), UART_TAG, "uart_num error");
ESP_RETURN_ON_FALSE((p_uart_obj[uart_num]), (-1), UART_TAG, "uart driver error");
ESP_RETURN_ON_FALSE((brk_len > 0 && brk_len < 256), (-1), UART_TAG, "break_num error");
// The hardware break (txd_brk) is only appended after a data byte is transmitted.
// To emit a standalone break without sending any data bytes, the idle-high TX line
// is driven low (space level) for brk_len bit periods by inverting the TXD signal.
uint32_t baud_rate = 0;
if (uart_get_baudrate(uart_num, &baud_rate) != ESP_OK || baud_rate == 0) {
return -1;
}
// Duration of the break in microseconds = brk_len bit periods at the current baudrate.
uint32_t brk_us = (uint32_t)(((uint64_t)brk_len * 1000000ULL + baud_rate - 1) / baud_rate);
//lock for uart_tx to serialize with other TX operations
xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (TickType_t)portMAX_DELAY);
#if PROTECT_APB
esp_pm_lock_acquire(p_uart_obj[uart_num]->pm_lock);
#endif
//Wait until any previously queued/buffered data has been fully transmitted
//so that the break signal is placed on an idle line.
while (!uart_hal_is_tx_idle(&(uart_context[uart_num].hal))) {
esp_rom_delay_us(1);
}
//Drive the idle-high TX line low to generate the break condition.
UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock));
uart_hal_inverse_signal(&(uart_context[uart_num].hal), UART_SIGNAL_TXD_INV);
UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock));
esp_rom_delay_us(brk_us);
//Restore the TX line to its normal (non-inverted) idle-high level.
UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock));
uart_hal_inverse_signal(&(uart_context[uart_num].hal), 0);
UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock));
#if PROTECT_APB
esp_pm_lock_release(p_uart_obj[uart_num]->pm_lock);
#endif
xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
return 0;
}Who is online
Users browsing this forum: ChatGPT-User and 3 guests