diff --git a/CMakeLists.txt b/CMakeLists.txt index 7338750..b5a4e36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,8 +12,8 @@ pico_sdk_init() add_executable( main main.c - - + ${CMAKE_CURRENT_LIST_DIR}/uart_tx.pio + ${CMAKE_CURRENT_LIST_DIR}/uart_rx.pio ) diff --git a/main.c b/main.c index 8949ed7..4d7aea9 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,64 @@ #include "main.h" +int IM1253B_INIT(void) +{ +/* + // 初始化UART + uart_init(UART0, BAUD_RATE); + gpio_set_function(UART0_TX_PIN, GPIO_FUNC_UART); + gpio_set_function(UART0_RX_PIN, GPIO_FUNC_UART); + uart_set_hw_flow(UART0, false, false); + uart_set_format(UART0, DATA_BITS, STOP_BITS, PARITY); + sleep_ms(10); +*/ + uint tx_offset = pio_add_program(IM1253B_PIO, &uart_tx_program); + uart_tx_program_init(IM1253B_PIO, IM1253B_PIO_SM_TX, tx_offset, IM1253B_PIO_TX_PIN, IM1253B_PIO_SERIAL_BAUD); + + uint rx_offset = pio_add_program(IM1253B_PIO, &uart_rx_program); + uart_rx_program_init(IM1253B_PIO, IM1253B_PIO_SM_RX, rx_offset, IM1253B_PIO_RX_PIN, IM1253B_PIO_SERIAL_BAUD); + + return 0; +} + +int IM1253B_PIO_UART_TX_DATA(PIO pio, uint sm, uint8_t *DATA, int DATA_LEN) { + + for (int i = 0; i < DATA_LEN; i++) { + uart_tx_program_putc(pio, sm, DATA[i]); + sleep_ms(1); + } + + return 0; +} + +int IM1253B_PIO_UART_RX_DATA(PIO pio, uint sm, uint8_t *DATA, int DATA_LEN) { + char c = '\0'; + int received_count = 0; + int timeout_ms = 100; // 设置较长的超时时间 + + while (received_count < DATA_LEN && timeout_ms > 0) { + if (uart_rx_program_available(pio, sm)) { + c = uart_rx_program_getc(pio, sm); + DATA[received_count++] = c; + printf("0x%X ", c); + if (c == '\n') { + // 接收到换行符,停止接收数据 + break; + } + } else { + // 没有接收到数据,继续等待 + sleep_ms(1); + timeout_ms--; + } + } + + if (received_count == 0) { + // 没有接收到有效数据,可以进行相应的处理 + return -1; + } + + return received_count; +} + unsigned int calccrc(unsigned char crcbuf, unsigned int crc) { unsigned char i; @@ -54,14 +113,16 @@ void read_data(void) Tx_Buffer[7] = crcnow.byte[0]; // 发送数据 - uart_write_blocking(UART0, Tx_Buffer, 8); + //uart_write_blocking(UART0, Tx_Buffer, 8); + IM1253B_PIO_UART_TX_DATA(IM1253B_PIO, IM1253B_PIO_SM_TX, Tx_Buffer, 8); sleep_ms(10); // 接收数据 uint8_t _DATA[37] = { 0 }; - uart_read_blocking(UART0, _DATA, 37); + //uart_read_blocking(UART0, _DATA, 37); + IM1253B_PIO_UART_RX_DATA(IM1253B_PIO, IM1253B_PIO_SM_RX, _DATA, 37); for (i = 0; i <= 37 - 1; i++) { - //printf("0x%X ", _DATA[i]); + printf("0x%X ", _DATA[i]); Rx_Buffer[i] = _DATA[i]; } sleep_ms(10); @@ -152,14 +213,7 @@ static uint16_t IM1253B(void) { static int i = 0; - // 初始化UART - uart_init(UART0, BAUD_RATE); - gpio_set_function(UART0_TX_PIN, GPIO_FUNC_UART); - gpio_set_function(UART0_RX_PIN, GPIO_FUNC_UART); - uart_set_hw_flow(UART0, false, false); - uart_set_format(UART0, DATA_BITS, STOP_BITS, PARITY); - sleep_ms(10); - + /* // 官方软件内部按钮发送的数据 // 电能清零 TX[13]:01 10 00 4B 00 02 04 00 00 00 00 B6 2C @@ -211,6 +265,8 @@ int main(void) sec = 0; printf("IM1253B Module\n"); + + IM1253B_INIT(); while (1) { watchdog_update(); // 喂狗 diff --git a/main.h b/main.h index ca5338b..62fc8ea 100644 --- a/main.h +++ b/main.h @@ -14,15 +14,25 @@ #include "hardware/pwm.h" #include "hardware/adc.h" +#include "hardware/pio.h" + #define UART0 uart0 #define BAUD_RATE 4800 #define DATA_BITS 8 #define STOP_BITS 1 #define PARITY UART_PARITY_NONE - #define UART0_TX_PIN 1 #define UART0_RX_PIN 0 +#include "uart_tx.pio.h" +#include "uart_rx.pio.h" +#define IM1253B_PIO pio0 +#define IM1253B_PIO_TX_PIN 19 // 接 IM1253B (TX) PIN +#define IM1253B_PIO_RX_PIN 20 // 接 IM1253B (RX) PIN +#define IM1253B_PIO_SM_TX 0 +#define IM1253B_PIO_SM_RX 1 +#define IM1253B_PIO_SERIAL_BAUD 4800 + int Read_ID = 0x01; unsigned char Tx_Buffer[8]; unsigned char Rx_Buffer[40]; diff --git a/uart_rx.pio b/uart_rx.pio new file mode 100644 index 0000000..54a6577 --- /dev/null +++ b/uart_rx.pio @@ -0,0 +1,94 @@ +; +; Copyright (c) 2020 Raspberry Pi (Trading) Ltd. +; +; SPDX-License-Identifier: BSD-3-Clause +; + +.program uart_rx_mini + +; Minimum viable 8n1 UART receiver. Wait for the start bit, then sample 8 bits +; with the correct timing. +; IN pin 0 is mapped to the GPIO used as UART RX. +; Autopush must be enabled, with a threshold of 8. + + wait 0 pin 0 ; Wait for start bit + set x, 7 [10] ; Preload bit counter, delay until eye of first data bit +bitloop: ; Loop 8 times + in pins, 1 ; Sample data + jmp x-- bitloop [6] ; Each iteration is 8 cycles + +% c-sdk { +#include "hardware/clocks.h" +#include "hardware/gpio.h" + +static inline void uart_rx_mini_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) { + pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false); + pio_gpio_init(pio, pin); + gpio_pull_up(pin); + + pio_sm_config c = uart_rx_mini_program_get_default_config(offset); + sm_config_set_in_pins(&c, pin); // for WAIT, IN + // Shift to right, autopush enabled + sm_config_set_in_shift(&c, true, true, 8); + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); + // SM transmits 1 bit per 8 execution cycles. + float div = (float)clock_get_hz(clk_sys) / (8 * baud); + sm_config_set_clkdiv(&c, div); + + pio_sm_init(pio, sm, offset, &c); + pio_sm_set_enabled(pio, sm, true); +} +%} + +.program uart_rx + +; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and +; break conditions more gracefully. +; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX. + +start: + wait 0 pin 0 ; Stall until start bit is asserted + set x, 7 [10] ; Preload bit counter, then delay until halfway through +bitloop: ; the first data bit (12 cycles incl wait, set). + in pins, 1 ; Shift data bit into ISR + jmp x-- bitloop [6] ; Loop 8 times, each loop iteration is 8 cycles + jmp pin good_stop ; Check stop bit (should be high) + + irq 4 rel ; Either a framing error or a break. Set a sticky flag, + wait 1 pin 0 ; and wait for line to return to idle state. + jmp start ; Don't push data if we didn't see good framing. + +good_stop: ; No delay before returning to start; a little slack is + push ; important in case the TX clock is slightly too fast. + + +% c-sdk { +static inline void uart_rx_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) { + pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false); + pio_gpio_init(pio, pin); + gpio_pull_up(pin); + + pio_sm_config c = uart_rx_program_get_default_config(offset); + sm_config_set_in_pins(&c, pin); // for WAIT, IN + sm_config_set_jmp_pin(&c, pin); // for JMP + // Shift to right, autopush disabled + sm_config_set_in_shift(&c, true, false, 32); + // Deeper FIFO as we're not doing any TX + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); + // SM transmits 1 bit per 8 execution cycles. + float div = (float)clock_get_hz(clk_sys) / (8 * baud); + sm_config_set_clkdiv(&c, div); + + pio_sm_init(pio, sm, offset, &c); + pio_sm_set_enabled(pio, sm, true); +} + +static inline char uart_rx_program_getc(PIO pio, uint sm) { + // 8-bit read from the uppermost byte of the FIFO, as data is left-justified + io_rw_8 *rxfifo_shift = (io_rw_8*)&pio->rxf[sm] + 3; + while (pio_sm_is_rx_fifo_empty(pio, sm)) + tight_loop_contents(); + return (char)*rxfifo_shift; +} + +%} diff --git a/uart_rx.pio.h b/uart_rx.pio.h new file mode 100644 index 0000000..05320e3 --- /dev/null +++ b/uart_rx.pio.h @@ -0,0 +1,130 @@ +// -------------------------------------------------- // +// This file is autogenerated by pioasm; do not edit! // +// -------------------------------------------------- // + +#pragma once + +#if !PICO_NO_HARDWARE +#include "hardware/pio.h" +#endif + +// ------------ // +// uart_rx_mini // +// ------------ // + +#define uart_rx_mini_wrap_target 0 +#define uart_rx_mini_wrap 3 + +static const uint16_t uart_rx_mini_program_instructions[] = { + // .wrap_target + 0x2020, // 0: wait 0 pin, 0 + 0xea27, // 1: set x, 7 [10] + 0x4001, // 2: in pins, 1 + 0x0642, // 3: jmp x--, 2 [6] + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program uart_rx_mini_program = { + .instructions = uart_rx_mini_program_instructions, + .length = 4, + .origin = -1, +}; + +static inline pio_sm_config uart_rx_mini_program_get_default_config(uint offset) +{ + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + uart_rx_mini_wrap_target, offset + uart_rx_mini_wrap); + return c; +} + +#include "hardware/clocks.h" +#include "hardware/gpio.h" +static inline void uart_rx_mini_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) +{ + pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false); + pio_gpio_init(pio, pin); + gpio_pull_up(pin); + pio_sm_config c = uart_rx_mini_program_get_default_config(offset); + sm_config_set_in_pins(&c, pin); // for WAIT, IN + // Shift to right, autopush enabled + sm_config_set_in_shift(&c, true, true, 8); + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); + // SM transmits 1 bit per 8 execution cycles. + float div = (float)clock_get_hz(clk_sys) / (8 * baud); + sm_config_set_clkdiv(&c, div); + pio_sm_init(pio, sm, offset, &c); + pio_sm_set_enabled(pio, sm, true); +} + +#endif + +// ------- // +// uart_rx // +// ------- // + +#define uart_rx_wrap_target 0 +#define uart_rx_wrap 8 + +static const uint16_t uart_rx_program_instructions[] = { + // .wrap_target + 0x2020, // 0: wait 0 pin, 0 + 0xea27, // 1: set x, 7 [10] + 0x4001, // 2: in pins, 1 + 0x0642, // 3: jmp x--, 2 [6] + 0x00c8, // 4: jmp pin, 8 + 0xc014, // 5: irq nowait 4 rel + 0x20a0, // 6: wait 1 pin, 0 + 0x0000, // 7: jmp 0 + 0x8020, // 8: push block + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program uart_rx_program = { + .instructions = uart_rx_program_instructions, + .length = 9, + .origin = -1, +}; + +static inline pio_sm_config uart_rx_program_get_default_config(uint offset) +{ + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + uart_rx_wrap_target, offset + uart_rx_wrap); + return c; +} + +static inline void uart_rx_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) +{ + pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false); + pio_gpio_init(pio, pin); + gpio_pull_up(pin); + pio_sm_config c = uart_rx_program_get_default_config(offset); + sm_config_set_in_pins(&c, pin); // for WAIT, IN + sm_config_set_jmp_pin(&c, pin); // for JMP + // Shift to right, autopush disabled + sm_config_set_in_shift(&c, true, false, 32); + // Deeper FIFO as we're not doing any TX + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); + // SM transmits 1 bit per 8 execution cycles. + float div = (float)clock_get_hz(clk_sys) / (8 * baud); + sm_config_set_clkdiv(&c, div); + pio_sm_init(pio, sm, offset, &c); + pio_sm_set_enabled(pio, sm, true); +} + +static inline bool uart_rx_program_available(PIO pio, uint sm) +{ + return !pio_sm_is_rx_fifo_empty(pio, sm); +} + +static inline char uart_rx_program_getc(PIO pio, uint sm) +{ + // 8-bit read from the uppermost byte of the FIFO, as data is left-justified + io_rw_8 *rxfifo_shift = (io_rw_8 *) & pio->rxf[sm] + 3; + while (pio_sm_is_rx_fifo_empty(pio, sm)) + tight_loop_contents(); + return (char)*rxfifo_shift; +} + +#endif diff --git a/uart_tx.pio b/uart_tx.pio new file mode 100644 index 0000000..b1320f6 --- /dev/null +++ b/uart_tx.pio @@ -0,0 +1,61 @@ +; +; Copyright (c) 2020 Raspberry Pi (Trading) Ltd. +; +; SPDX-License-Identifier: BSD-3-Clause +; + +.program uart_tx +.side_set 1 opt + +; An 8n1 UART transmit program. +; OUT pin 0 and side-set pin 0 are both mapped to UART TX pin. + + pull side 1 [7] ; Assert stop bit, or stall with line in idle state + set x, 7 side 0 [7] ; Preload bit counter, assert start bit for 8 clocks +bitloop: ; This loop will run 8 times (8n1 UART) + out pins, 1 ; Shift 1 bit from OSR to the first OUT pin + jmp x-- bitloop [6] ; Each loop iteration is 8 cycles. + + +% c-sdk { +#include "hardware/clocks.h" + +static inline void uart_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx, uint baud) { + // Tell PIO to initially drive output-high on the selected pin, then map PIO + // onto that pin with the IO muxes. + pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx); + pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx); + pio_gpio_init(pio, pin_tx); + + pio_sm_config c = uart_tx_program_get_default_config(offset); + + // OUT shifts to right, no autopull + sm_config_set_out_shift(&c, true, false, 32); + + // We are mapping both OUT and side-set to the same pin, because sometimes + // we need to assert user data onto the pin (with OUT) and sometimes + // assert constant values (start/stop bit) + sm_config_set_out_pins(&c, pin_tx, 1); + sm_config_set_sideset_pins(&c, pin_tx); + + // We only need TX, so get an 8-deep FIFO! + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); + + // SM transmits 1 bit per 8 execution cycles. + float div = (float)clock_get_hz(clk_sys) / (8 * baud); + sm_config_set_clkdiv(&c, div); + + pio_sm_init(pio, sm, offset, &c); + pio_sm_set_enabled(pio, sm, true); +} + +static inline void uart_tx_program_putc(PIO pio, uint sm, char c) { + pio_sm_put_blocking(pio, sm, (uint32_t)c); +} + +static inline void uart_tx_program_puts(PIO pio, uint sm, const char *s) { + while (*s) + uart_tx_program_putc(pio, sm, *s++); +} + +%} diff --git a/uart_tx.pio.h b/uart_tx.pio.h new file mode 100644 index 0000000..bd24f10 --- /dev/null +++ b/uart_tx.pio.h @@ -0,0 +1,78 @@ +// -------------------------------------------------- // +// This file is autogenerated by pioasm; do not edit! // +// -------------------------------------------------- // + +#pragma once + +#if !PICO_NO_HARDWARE +#include "hardware/pio.h" +#endif + +// ------- // +// uart_tx // +// ------- // + +#define uart_tx_wrap_target 0 +#define uart_tx_wrap 3 + +static const uint16_t uart_tx_program_instructions[] = { + // .wrap_target + 0x9fa0, // 0: pull block side 1 [7] + 0xf727, // 1: set x, 7 side 0 [7] + 0x6001, // 2: out pins, 1 + 0x0642, // 3: jmp x--, 2 [6] + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program uart_tx_program = { + .instructions = uart_tx_program_instructions, + .length = 4, + .origin = -1, +}; + +static inline pio_sm_config uart_tx_program_get_default_config(uint offset) +{ + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + uart_tx_wrap_target, offset + uart_tx_wrap); + sm_config_set_sideset(&c, 2, true, false); + return c; +} + +#include "hardware/clocks.h" +static inline void uart_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx, uint baud) +{ + // Tell PIO to initially drive output-high on the selected pin, then map PIO + // onto that pin with the IO muxes. + pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx); + pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx); + pio_gpio_init(pio, pin_tx); + pio_sm_config c = uart_tx_program_get_default_config(offset); + // OUT shifts to right, no autopull + sm_config_set_out_shift(&c, true, false, 32); + // We are mapping both OUT and side-set to the same pin, because sometimes + // we need to assert user data onto the pin (with OUT) and sometimes + // assert constant values (start/stop bit) + sm_config_set_out_pins(&c, pin_tx, 1); + sm_config_set_sideset_pins(&c, pin_tx); + // We only need TX, so get an 8-deep FIFO! + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); + // SM transmits 1 bit per 8 execution cycles. + float div = (float)clock_get_hz(clk_sys) / (8 * baud); + sm_config_set_clkdiv(&c, div); + pio_sm_init(pio, sm, offset, &c); + pio_sm_set_enabled(pio, sm, true); +} + +static inline void uart_tx_program_putc(PIO pio, uint sm, char c) +{ + pio_sm_put_blocking(pio, sm, (uint32_t) c); +} + +static inline void uart_tx_program_puts(PIO pio, uint sm, const char *s) +{ + while (*s) + uart_tx_program_putc(pio, sm, *s++); +} + +#endif