boarchuz / HULP

ESP32 ULP Coprocessor Helper
MIT License
180 stars 18 forks source link

feature request: UART with parity bit #26

Open antonmeyer opened 1 year ago

antonmeyer commented 1 year ago

could you extend the UART with parity bit?

boarchuz commented 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);
    }
}
antonmeyer commented 1 year ago

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(...).

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);
}

}

— 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.