Open antonmeyer opened 1 year ago
Hi @antonmeyer ,
Below I've modified the UART example to transmit the parity bit, and check the parity bit when receiving. I've tested at 9600 and 115200.
Would you mind testing it on your side, too? And let me know if there's anything in particular you need supported.
I'll clean it up then so it's much easier to include and customise. It will probably have the same usage as the existing ones, eg. M_INCLUDE_UART_RX_PARITY(...) and M_INCLUDE_UART_TX_PARITY(...).
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "driver/rtc_io.h"
#include "driver/gpio.h"
#include "soc/rtc.h"
#include "esp_log.h"
#include "esp_attr.h"
#include "hulp.h"
#include "hulp_uart.h"
#include "sdkconfig.h"
#define PIN_ULP_TX GPIO_NUM_25
#define PIN_ULP_RX GPIO_NUM_26
#define BAUD_RATE 9600
#define ULP_STRING_GREETING "Hello, what's your name?\n"
#define ULP_STRING_REPLY_START "Nice to meet you, "
#define ULP_STRING_REPLY_END "! I'm a ULP Coprocessor.\n"
#define ULP_RX_MAX_LEN 32
RTC_SLOW_ATTR ulp_var_t ulp_greeting HULP_UART_STRING_RESERVE(ULP_STRING_GREETING);
RTC_SLOW_ATTR ulp_var_t ulp_reply_start HULP_UART_STRING_RESERVE(ULP_STRING_REPLY_START);
RTC_SLOW_ATTR ulp_var_t ulp_reply_end HULP_UART_STRING_RESERVE(ULP_STRING_REPLY_END);
#define ULP_STRING_DEBUG "PARITY ERROR\n"
RTC_SLOW_ATTR ulp_var_t ulp_debug_str HULP_UART_STRING_RESERVE(ULP_STRING_DEBUG);
RTC_SLOW_ATTR ulp_var_t ulp_rx_buffer HULP_UART_STRING_BUFFER(ULP_RX_MAX_LEN);
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
#endif
static RTC_SLOW_ATTR ulp_var_t ulp_subroutine_return_pc;
void init_ulp()
{
enum
{
LBL_TX_GREET,
LBL_TX_GREET_RETURN,
LBL_RX_RESPONSE,
LBL_RX_RESPONSE_RETURN,
LBL_TX_REPLY_START,
LBL_TX_REPLY_START_RETURN,
LBL_TX_RESPONSE,
LBL_TX_RESPONSE_RETURN,
LBL_TX_REPLY_END,
LBL_TX_REPLY_END_RETURN,
LBL_SUBROUTINE_TX_ENTRY,
LBL_SUBROUTINE_RX_ENTRY,
LBL_UART_RX_NEXT_BYTE,
LBL_UART_RX_DONE,
LBL_UART_RX_NEXT_BIT,
LBL_UART_RX_START_DATA_BITS,
LBL_UART_RX_READ_FIRST_BIT,
LBL_UART_RX_PARITY_ERROR,
LBL_UART_TX_ENTRY,
LBL_UART_TX_DONE,
LBL_UART_TX_NEXT_BYTE,
LBL_UART_TX_FIRST_BYTE,
LBL_UART_TX_NEXT_BIT,
LBL_UART_TX_BIT_IN_R0,
LBL_UART_TX_NEXT_WORD,
LBL_UART_TX_0_BIT,
LBL_UART_TX_BIT_DONE,
LBL_UART_TX_PARITY_BIT,
LBL_UART_RETURN,
};
const ulp_insn_t program[] = {
//Request name
I_MOVI(R2, 0),
M_MOVL(R3, LBL_TX_GREET_RETURN),
I_PUT(R3, R2, ulp_subroutine_return_pc),
I_MOVO(R1, ulp_greeting),
M_BX(LBL_SUBROUTINE_TX_ENTRY),
M_LABEL(LBL_TX_GREET_RETURN),
//Read response (name) into buffer
I_MOVI(R2, 0),
M_MOVL(R3, LBL_RX_RESPONSE_RETURN),
I_PUT(R3, R2, ulp_subroutine_return_pc),
I_MOVO(R1, ulp_rx_buffer),
M_BX(LBL_SUBROUTINE_RX_ENTRY),
M_LABEL(LBL_RX_RESPONSE_RETURN),
//Start intro
I_MOVI(R2, 0),
M_MOVL(R3, LBL_TX_REPLY_START_RETURN),
I_PUT(R3, R2, ulp_subroutine_return_pc),
I_MOVO(R1, ulp_reply_start),
M_BX(LBL_SUBROUTINE_TX_ENTRY),
M_LABEL(LBL_TX_REPLY_START_RETURN),
//Echo the name that was just received
I_MOVI(R2, 0),
M_MOVL(R3, LBL_TX_RESPONSE_RETURN),
I_PUT(R3, R2, ulp_subroutine_return_pc),
I_MOVO(R1, ulp_rx_buffer),
M_BX(LBL_SUBROUTINE_TX_ENTRY),
M_LABEL(LBL_TX_RESPONSE_RETURN),
//End intro
I_MOVI(R2, 0),
M_MOVL(R3, LBL_TX_REPLY_END_RETURN),
I_PUT(R3, R2, ulp_subroutine_return_pc),
I_MOVO(R1, ulp_reply_end),
M_BX(LBL_SUBROUTINE_TX_ENTRY),
M_LABEL(LBL_TX_REPLY_END_RETURN),
//Sleep
I_WAKE(),
I_HALT(),
//Dependencies for UART
M_LABEL(LBL_SUBROUTINE_RX_ENTRY),
I_MOVI(R2, 0), // R2 == rx_len
M_LABEL(LBL_UART_RX_NEXT_BYTE),
I_LD(R0, R1, 0), // Load metadata (note: buffer size in R0 upper 8 bits)
I_SUBR(R0, R0, R2), // Check if full (note: current received length in R2 upper 8 bits)
M_BL(LBL_UART_RX_DONE, 1 << 8),
I_GPIO_READ(PIN_ULP_RX), /*Wait here until pin goes low (start bit)*/
I_BGE(-1, 1),
I_STAGE_RST(),
// Delay 72 for 115200
I_DELAY(({
uint32_t fast_clk_freq = hulp_get_fast_clk_freq();
fast_clk_freq += (fast_clk_freq + 1) / 2;
fast_clk_freq += BAUD_RATE / 2;
fast_clk_freq /= BAUD_RATE;
fast_clk_freq -= 39;
(uint16_t)fast_clk_freq;
})),
M_LABEL(LBL_UART_RX_NEXT_BIT),
// Delay until approx middle of bit ready (delay = I_DELAY(x) + loop execution overhead)
I_STAGE_INC(1), // Increment bit count
// If this is first bit, go delay and read level
M_BSLT(LBL_UART_RX_READ_FIRST_BIT, 2),
I_ADDR(R1, R1, R0), // Toggle bit15 for odd/even bit count for partiy check
I_RSHI(R3, R3, 1), // Rx bit -> reg_buf:15
I_ORR(R3, R3, R0),
// Delay 34 for 115200
I_DELAY((uint16_t)((hulp_get_fast_clk_freq() + (BAUD_RATE/2)) / (BAUD_RATE) - 40)),
M_LABEL(LBL_UART_RX_READ_FIRST_BIT),
I_GPIO_READ(PIN_ULP_RX),
I_LSHI(R0, R0, 15),
M_BSLT(LBL_UART_RX_NEXT_BIT, 1 + 8), // If this is a start delay or data bit then loop
// R1[15] == odd number of 1 bits, R0[15] == parity_bit
I_ADDR(R0, R1, R0), // Add bit to lower bits of len for parity check
I_ANDI(R1, R1, (uint16_t)((1<<11)-1)), // Clear parity bit
M_BGE(LBL_UART_RX_PARITY_ERROR, (1 << 11)),
// Store the byte. ulpstring =one word metadata, then 2 chars in every word thereafter, so offset = 1+length/2
I_RSHI(R0, R2, 1 + 8), /* length in upper 8 bits, shift 8+1 to halve it */
I_ADDR(R0, R1, R0), /* add to string ptr */
I_ST(R3, R0, 1), /* then I_ST with 1 offset (as first word is metadata)) */
I_GPIO_READ(PIN_ULP_RX), /* Wait here until pin goes high to sync with stop bit*/
I_BL(-1, 1),
I_SUBI(R0, R3, ('\n')<<8), /* Most recent byte is in upper 8 bits, so subtract (termination_char)<<8*/
M_BL(LBL_UART_RX_DONE, 1<<8), /* If upper bits are 8b0 then byte matches termination_char so end */
I_ADDI(R2, R2, 1<<8), /* else increment length and loop back to beginning of new byte */
M_BGE(LBL_UART_RX_NEXT_BYTE, 0),
M_LABEL(LBL_UART_RX_PARITY_ERROR),
// Set length to 0 and fall through to save metadata
I_MOVI(R2, 0),
#if 1 // Debugging
I_LD(R3, R1, 0), /*Load the metadata (termination char / buffer full branches here)*/
I_ANDI(R3, R3, 0xFF<<8), /*Update metadata with received length*/
I_RSHI(R2, R2, 8),
I_ORR(R3, R3, R2),
I_ST(R3, R1, 0), /* This I_ST also sets updated flag on metadata var */
I_MOVO(R1, ulp_debug_str),
M_BX(LBL_SUBROUTINE_TX_ENTRY),
#endif
M_LABEL(LBL_UART_RX_DONE),
I_LD(R3, R1, 0), /*Load the metadata (termination char / buffer full branches here)*/
I_ANDI(R3, R3, 0xFF<<8), /*Update metadata with received length*/
I_RSHI(R2, R2, 8),
I_ORR(R3, R3, R2),
I_ST(R3, R1, 0), /* This I_ST also sets updated flag on metadata var */
M_BX(LBL_UART_RETURN),
M_LABEL(LBL_SUBROUTINE_TX_ENTRY),
#define ULP_UART_TX_STAGE_INC_VAL 28
I_LD(R3, R1, 0),
I_ANDI(R3, R3, 0xFF), // R3 = length
M_LABEL(LBL_UART_TX_NEXT_WORD),
I_ADDI(R1, R1, 1), // R1 = pointer + byte index
I_LD(R2, R1, 0), // R2 = 2 data bytes
I_STAGE_RST(),
M_LABEL(LBL_UART_TX_NEXT_BYTE),
I_SUBI(R3, R3, 1), // --len
M_BXF(LBL_UART_TX_DONE),
// Start
I_HULP_UART_TX_LOW((PIN_ULP_TX)),
I_DELAY((uint16_t)(hulp_get_fast_clk_freq() / (BAUD_RATE) - 19)),
M_LABEL(LBL_UART_TX_NEXT_BIT),
I_ANDI(R0, R2, 1),
I_RSHI(R2, R2, 1),
M_LABEL(LBL_UART_TX_BIT_IN_R0),
M_BL(LBL_UART_TX_0_BIT, 1),
I_HULP_UART_TX_HIGH((PIN_ULP_TX)),
I_ADDI(R1, R1, 1 << 15),
I_DELAY((uint16_t)((hulp_get_fast_clk_freq() / (BAUD_RATE)) - 42)),
M_LABEL(LBL_UART_TX_BIT_DONE),
I_STAGE_INC(ULP_UART_TX_STAGE_INC_VAL),
// if data bit, go to tx_next_bit
M_BSLT(LBL_UART_TX_NEXT_BIT, MIN(((uint8_t)((8) * ULP_UART_TX_STAGE_INC_VAL)), ((uint8_t)((8+1+8) * ULP_UART_TX_STAGE_INC_VAL)))),
// Prepare parity
I_RSHI(R0, R1, 15),
// if parity, tx parity bit
M_BSLT(LBL_UART_TX_BIT_IN_R0, MIN(((uint8_t)((8+1) * ULP_UART_TX_STAGE_INC_VAL)), ((uint8_t)((8+1+8+1) * ULP_UART_TX_STAGE_INC_VAL)))),
// else end byte and loop to next byte/word
I_HULP_UART_TX_HIGH((PIN_ULP_TX)),
I_DELAY((uint16_t)(hulp_get_fast_clk_freq() / (BAUD_RATE) - 0)),
// Note: first byte stage = 252, second byte stage = 248
M_BSGE(LBL_UART_TX_NEXT_BYTE, (uint8_t)((8+1) * ULP_UART_TX_STAGE_INC_VAL)),
M_BX(LBL_UART_TX_NEXT_WORD),
M_LABEL(LBL_UART_TX_0_BIT),
I_HULP_UART_TX_LOW((PIN_ULP_TX)),
I_DELAY((uint16_t)((hulp_get_fast_clk_freq() / (BAUD_RATE)) - 44)),
M_BX(LBL_UART_TX_BIT_DONE),
M_LABEL(LBL_UART_TX_DONE),
M_LABEL(LBL_UART_RETURN),
I_MOVI(R2, 0),
I_GET(R3, R2, ulp_subroutine_return_pc),
I_BXR(R3),
};
// Set the contents of string buffers
if(
hulp_uart_string_set(ulp_greeting, ARRAY_SIZE(ulp_greeting), (const char*)ULP_STRING_GREETING) < 0 ||
hulp_uart_string_set(ulp_reply_start, ARRAY_SIZE(ulp_reply_start), ULP_STRING_REPLY_START) < 0 ||
hulp_uart_string_set(ulp_reply_end, ARRAY_SIZE(ulp_reply_end), ULP_STRING_REPLY_END) < 0 ||
hulp_uart_string_set(ulp_debug_str, ARRAY_SIZE(ulp_debug_str), ULP_STRING_DEBUG) < 0
)
{
abort();
}
#if CONFIG_HULP_UART_TX_OD
ESP_ERROR_CHECK(hulp_configure_pin(PIN_ULP_TX, RTC_GPIO_MODE_DISABLED, GPIO_PULLUP_ONLY, 0));
#else
ESP_ERROR_CHECK(hulp_configure_pin(PIN_ULP_TX, RTC_GPIO_MODE_OUTPUT_ONLY, GPIO_FLOATING, 1));
#endif
ESP_ERROR_CHECK(hulp_configure_pin(PIN_ULP_RX, RTC_GPIO_MODE_INPUT_ONLY, GPIO_PULLUP_ONLY, 0));
ESP_ERROR_CHECK(hulp_ulp_load(program, sizeof(program), 2/* 10ULL */ * 1000 * 1000, 0));
ESP_ERROR_CHECK(hulp_ulp_run(0));
}
void ulp_isr(void *task_handle_ptr)
{
xTaskNotifyFromISR(*(TaskHandle_t*)task_handle_ptr, 0, eNoAction, NULL);
}
void app_main()
{
// ULP will trigger an interrupt when a new UART string is received. Set up here.
TaskHandle_t main_handle = xTaskGetCurrentTaskHandle();
hulp_ulp_isr_register(&ulp_isr, &main_handle);
hulp_ulp_interrupt_en();
// Load and start the program.
init_ulp();
for (;;)
{
// Block until notified by ULP+ISR
xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
// Get the contents of the buffer and display
char name[ULP_RX_MAX_LEN + 1];
int len = hulp_uart_string_get(ulp_rx_buffer, name, sizeof(name), false);
if(len < 0)
{
abort();
}
printf("ULP RX String (%d): %s\n", len, name);
}
}
woh, thank you very much I will test it within the next weeks. I’ve just started with the subject of ULP, that will be my first project.
Am 30.05.2023 um 12:53 schrieb boarchuz @.***>:
Hi @antonmeyer https://github.com/antonmeyer ,
Below I've modified the UART example to transmit the parity bit, and check the parity bit when receiving. I've tested at 9600 and 115200.
Would you mind testing it on your side, too? And let me know if there's anything in particular you need supported.
I'll clean it up then so it's much easier to include and customise. It will probably have the same usage as the existing ones, eg. M_INCLUDE_UART_RX_PARITY(...) and M_INCLUDE_UART_TX_PARITY(...).
RTC_SLOW_ATTR ulp_var_t ulp_greeting HULP_UART_STRING_RESERVE(ULP_STRING_GREETING); RTC_SLOW_ATTR ulp_var_t ulp_reply_start HULP_UART_STRING_RESERVE(ULP_STRING_REPLY_START); RTC_SLOW_ATTR ulp_var_t ulp_reply_end HULP_UART_STRING_RESERVE(ULP_STRING_REPLY_END);
RTC_SLOW_ATTR ulp_var_t ulp_debug_str HULP_UART_STRING_RESERVE(ULP_STRING_DEBUG);
RTC_SLOW_ATTR ulp_var_t ulp_rx_buffer HULP_UART_STRING_BUFFER(ULP_RX_MAX_LEN);
static RTC_SLOW_ATTR ulp_var_t ulp_subroutine_return_pc;
void init_ulp() { enum { LBL_TX_GREET, LBL_TX_GREET_RETURN,
LBL_RX_RESPONSE,
LBL_RX_RESPONSE_RETURN,
LBL_TX_REPLY_START,
LBL_TX_REPLY_START_RETURN,
LBL_TX_RESPONSE,
LBL_TX_RESPONSE_RETURN,
LBL_TX_REPLY_END,
LBL_TX_REPLY_END_RETURN,
LBL_SUBROUTINE_TX_ENTRY,
LBL_SUBROUTINE_RX_ENTRY,
LBL_UART_RX_NEXT_BYTE,
LBL_UART_RX_DONE,
LBL_UART_RX_NEXT_BIT,
LBL_UART_RX_START_DATA_BITS,
LBL_UART_RX_READ_FIRST_BIT,
LBL_UART_RX_PARITY_ERROR,
LBL_UART_TX_ENTRY,
LBL_UART_TX_DONE,
LBL_UART_TX_NEXT_BYTE,
LBL_UART_TX_FIRST_BYTE,
LBL_UART_TX_NEXT_BIT,
LBL_UART_TX_BIT_IN_R0,
LBL_UART_TX_NEXT_WORD,
LBL_UART_TX_0_BIT,
LBL_UART_TX_BIT_DONE,
LBL_UART_TX_PARITY_BIT,
LBL_UART_RETURN,
};
const ulp_insn_t program[] = {
//Request name
I_MOVI(R2, 0),
M_MOVL(R3, LBL_TX_GREET_RETURN),
I_PUT(R3, R2, ulp_subroutine_return_pc),
I_MOVO(R1, ulp_greeting),
M_BX(LBL_SUBROUTINE_TX_ENTRY),
M_LABEL(LBL_TX_GREET_RETURN),
//Read response (name) into buffer
I_MOVI(R2, 0),
M_MOVL(R3, LBL_RX_RESPONSE_RETURN),
I_PUT(R3, R2, ulp_subroutine_return_pc),
I_MOVO(R1, ulp_rx_buffer),
M_BX(LBL_SUBROUTINE_RX_ENTRY),
M_LABEL(LBL_RX_RESPONSE_RETURN),
//Start intro
I_MOVI(R2, 0),
M_MOVL(R3, LBL_TX_REPLY_START_RETURN),
I_PUT(R3, R2, ulp_subroutine_return_pc),
I_MOVO(R1, ulp_reply_start),
M_BX(LBL_SUBROUTINE_TX_ENTRY),
M_LABEL(LBL_TX_REPLY_START_RETURN),
//Echo the name that was just received
I_MOVI(R2, 0),
M_MOVL(R3, LBL_TX_RESPONSE_RETURN),
I_PUT(R3, R2, ulp_subroutine_return_pc),
I_MOVO(R1, ulp_rx_buffer),
M_BX(LBL_SUBROUTINE_TX_ENTRY),
M_LABEL(LBL_TX_RESPONSE_RETURN),
//End intro
I_MOVI(R2, 0),
M_MOVL(R3, LBL_TX_REPLY_END_RETURN),
I_PUT(R3, R2, ulp_subroutine_return_pc),
I_MOVO(R1, ulp_reply_end),
M_BX(LBL_SUBROUTINE_TX_ENTRY),
M_LABEL(LBL_TX_REPLY_END_RETURN),
//Sleep
I_WAKE(),
I_HALT(),
//Dependencies for UART
M_LABEL(LBL_SUBROUTINE_RX_ENTRY),
I_MOVI(R2, 0), // R2 == rx_len
M_LABEL(LBL_UART_RX_NEXT_BYTE),
I_LD(R0, R1, 0), // Load metadata (note: buffer size in R0 upper 8 bits)
I_SUBR(R0, R0, R2), // Check if full (note: current received length in R2 upper 8 bits)
M_BL(LBL_UART_RX_DONE, 1 << 8),
I_GPIO_READ(PIN_ULP_RX), /*Wait here until pin goes low (start bit)*/
I_BGE(-1, 1),
I_STAGE_RST(),
// Delay 72 for 115200
I_DELAY(({
uint32_t fast_clk_freq = hulp_get_fast_clk_freq();
fast_clk_freq += (fast_clk_freq + 1) / 2;
fast_clk_freq += BAUD_RATE / 2;
fast_clk_freq /= BAUD_RATE;
fast_clk_freq -= 39;
(uint16_t)fast_clk_freq;
})),
M_LABEL(LBL_UART_RX_NEXT_BIT),
// Delay until approx middle of bit ready (delay = I_DELAY(x) + loop execution overhead)
I_STAGE_INC(1), // Increment bit count
// If this is first bit, go delay and read level
M_BSLT(LBL_UART_RX_READ_FIRST_BIT, 2),
I_ADDR(R1, R1, R0), // Toggle bit15 for odd/even bit count for partiy check
I_RSHI(R3, R3, 1), // Rx bit -> reg_buf:15
I_ORR(R3, R3, R0),
// Delay 34 for 115200
I_DELAY((uint16_t)((hulp_get_fast_clk_freq() + (BAUD_RATE/2)) / (BAUD_RATE) - 40)),
M_LABEL(LBL_UART_RX_READ_FIRST_BIT),
I_GPIO_READ(PIN_ULP_RX),
I_LSHI(R0, R0, 15),
M_BSLT(LBL_UART_RX_NEXT_BIT, 1 + 8), // If this is a start delay or data bit then loop
// R1[15] == odd number of 1 bits, R0[15] == parity_bit
I_ADDR(R0, R1, R0), // Add bit to lower bits of len for parity check
I_ANDI(R1, R1, (uint16_t)((1<<11)-1)), // Clear parity bit
M_BGE(LBL_UART_RX_PARITY_ERROR, (1 << 11)),
// Store the byte. ulpstring =one word metadata, then 2 chars in every word thereafter, so offset = 1+length/2
I_RSHI(R0, R2, 1 + 8), /* length in upper 8 bits, shift 8+1 to halve it */
I_ADDR(R0, R1, R0), /* add to string ptr */
I_ST(R3, R0, 1), /* then I_ST with 1 offset (as first word is metadata)) */
I_GPIO_READ(PIN_ULP_RX), /* Wait here until pin goes high to sync with stop bit*/
I_BL(-1, 1),
I_SUBI(R0, R3, ('\n')<<8), /* Most recent byte is in upper 8 bits, so subtract (termination_char)<<8*/
M_BL(LBL_UART_RX_DONE, 1<<8), /* If upper bits are 8b0 then byte matches termination_char so end */
I_ADDI(R2, R2, 1<<8), /* else increment length and loop back to beginning of new byte */
M_BGE(LBL_UART_RX_NEXT_BYTE, 0),
M_LABEL(LBL_UART_RX_PARITY_ERROR),
// Set length to 0 and fall through to save metadata
I_MOVI(R2, 0),
#if 1 // Debugging
I_LD(R3, R1, 0), /*Load the metadata (termination char / buffer full branches here)*/
I_ANDI(R3, R3, 0xFF<<8), /*Update metadata with received length*/
I_RSHI(R2, R2, 8),
I_ORR(R3, R3, R2),
I_ST(R3, R1, 0), /* This I_ST also sets updated flag on metadata var */
I_MOVO(R1, ulp_debug_str),
M_BX(LBL_SUBROUTINE_TX_ENTRY),
#endif
M_LABEL(LBL_UART_RX_DONE),
I_LD(R3, R1, 0), /*Load the metadata (termination char / buffer full branches here)*/
I_ANDI(R3, R3, 0xFF<<8), /*Update metadata with received length*/
I_RSHI(R2, R2, 8),
I_ORR(R3, R3, R2),
I_ST(R3, R1, 0), /* This I_ST also sets updated flag on metadata var */
M_BX(LBL_UART_RETURN),
M_LABEL(LBL_SUBROUTINE_TX_ENTRY),
#define ULP_UART_TX_STAGE_INC_VAL 28
I_LD(R3, R1, 0),
I_ANDI(R3, R3, 0xFF), // R3 = length
M_LABEL(LBL_UART_TX_NEXT_WORD),
I_ADDI(R1, R1, 1), // R1 = pointer + byte index
I_LD(R2, R1, 0), // R2 = 2 data bytes
I_STAGE_RST(),
M_LABEL(LBL_UART_TX_NEXT_BYTE),
I_SUBI(R3, R3, 1), // --len
M_BXF(LBL_UART_TX_DONE),
// Start
I_HULP_UART_TX_LOW((PIN_ULP_TX)),
I_DELAY((uint16_t)(hulp_get_fast_clk_freq() / (BAUD_RATE) - 19)),
M_LABEL(LBL_UART_TX_NEXT_BIT),
I_ANDI(R0, R2, 1),
I_RSHI(R2, R2, 1),
M_LABEL(LBL_UART_TX_BIT_IN_R0),
M_BL(LBL_UART_TX_0_BIT, 1),
I_HULP_UART_TX_HIGH((PIN_ULP_TX)),
I_ADDI(R1, R1, 1 << 15),
I_DELAY((uint16_t)((hulp_get_fast_clk_freq() / (BAUD_RATE)) - 42)),
M_LABEL(LBL_UART_TX_BIT_DONE),
I_STAGE_INC(ULP_UART_TX_STAGE_INC_VAL),
// if data bit, go to tx_next_bit
M_BSLT(LBL_UART_TX_NEXT_BIT, MIN(((uint8_t)((8) * ULP_UART_TX_STAGE_INC_VAL)), ((uint8_t)((8+1+8) * ULP_UART_TX_STAGE_INC_VAL)))),
// Prepare parity
I_RSHI(R0, R1, 15),
// if parity, tx parity bit
M_BSLT(LBL_UART_TX_BIT_IN_R0, MIN(((uint8_t)((8+1) * ULP_UART_TX_STAGE_INC_VAL)), ((uint8_t)((8+1+8+1) * ULP_UART_TX_STAGE_INC_VAL)))),
// else end byte and loop to next byte/word
I_HULP_UART_TX_HIGH((PIN_ULP_TX)),
I_DELAY((uint16_t)(hulp_get_fast_clk_freq() / (BAUD_RATE) - 0)),
// Note: first byte stage = 252, second byte stage = 248
M_BSGE(LBL_UART_TX_NEXT_BYTE, (uint8_t)((8+1) * ULP_UART_TX_STAGE_INC_VAL)),
M_BX(LBL_UART_TX_NEXT_WORD),
M_LABEL(LBL_UART_TX_0_BIT),
I_HULP_UART_TX_LOW((PIN_ULP_TX)),
I_DELAY((uint16_t)((hulp_get_fast_clk_freq() / (BAUD_RATE)) - 44)),
M_BX(LBL_UART_TX_BIT_DONE),
M_LABEL(LBL_UART_TX_DONE),
M_LABEL(LBL_UART_RETURN),
I_MOVI(R2, 0),
I_GET(R3, R2, ulp_subroutine_return_pc),
I_BXR(R3),
};
// Set the contents of string buffers
if(
hulp_uart_string_set(ulp_greeting, ARRAY_SIZE(ulp_greeting), (const char*)ULP_STRING_GREETING) < 0 ||
hulp_uart_string_set(ulp_reply_start, ARRAY_SIZE(ulp_reply_start), ULP_STRING_REPLY_START) < 0 ||
hulp_uart_string_set(ulp_reply_end, ARRAY_SIZE(ulp_reply_end), ULP_STRING_REPLY_END) < 0 ||
hulp_uart_string_set(ulp_debug_str, ARRAY_SIZE(ulp_debug_str), ULP_STRING_DEBUG) < 0
)
{
abort();
}
ESP_ERROR_CHECK(hulp_configure_pin(PIN_ULP_TX, RTC_GPIO_MODE_DISABLED, GPIO_PULLUP_ONLY, 0));
ESP_ERROR_CHECK(hulp_configure_pin(PIN_ULP_TX, RTC_GPIO_MODE_OUTPUT_ONLY, GPIO_FLOATING, 1));
ESP_ERROR_CHECK(hulp_configure_pin(PIN_ULP_RX, RTC_GPIO_MODE_INPUT_ONLY, GPIO_PULLUP_ONLY, 0));
ESP_ERROR_CHECK(hulp_ulp_load(program, sizeof(program), 2/* 10ULL */ * 1000 * 1000, 0));
ESP_ERROR_CHECK(hulp_ulp_run(0));
}
void ulp_isr(void task_handle_ptr) { xTaskNotifyFromISR((TaskHandle_t*)task_handle_ptr, 0, eNoAction, NULL); }
void app_main() { // ULP will trigger an interrupt when a new UART string is received. Set up here. TaskHandle_t main_handle = xTaskGetCurrentTaskHandle(); hulp_ulp_isr_register(&ulp_isr, &main_handle); hulp_ulp_interrupt_en();
// Load and start the program.
init_ulp();
for (;;)
{
// Block until notified by ULP+ISR
xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
// Get the contents of the buffer and display
char name[ULP_RX_MAX_LEN + 1];
int len = hulp_uart_string_get(ulp_rx_buffer, name, sizeof(name), false);
if(len < 0)
{
abort();
}
printf("ULP RX String (%d): %s\n", len, name);
}
}
— Reply to this email directly, view it on GitHub https://github.com/boarchuz/HULP/issues/26#issuecomment-1568220283, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACZ4UM7EQSFDZB5CKHZVZNTXIXGUFANCNFSM6AAAAAAYRLTGZQ. You are receiving this because you were mentioned.
could you extend the UART with parity bit?