Compare commits

...

5 Commits

Author SHA1 Message Date
7f9fc40757 使用 PIO 串口(还未测试) 2024-03-31 18:04:35 +08:00
d329c022b5 Add Zeroing electrical energy 2024-03-12 11:28:55 +08:00
bbd32add04 Add module official documentation 2024-03-12 09:48:30 +08:00
c1b3f62543 Add MD file 2024-03-12 09:46:52 +08:00
d8c939bb79 Added temperature and frequency data 2024-03-12 09:41:56 +08:00
16 changed files with 539 additions and 51 deletions

View File

@@ -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
)

25
README.md Normal file
View File

@@ -0,0 +1,25 @@
# 基于 Raspberry Pico / Pico W 的电能计量模块IM1253B
* 可以计算电压、电流、功率、电能、功率因数、二氧化碳、温度、频率
## Build
```
# 使用WSL Debian GNU/Linux 12 (bookworm) 构建
# 确保Pico-SDK环境变量
export PICO_SDK_PATH=/mnt/c/Users/niuyuling/Desktop/raspberry-pico/SDK/pico-sdk
export PICO_EXTRAS_PATH=/mnt/c/Users/niuyuling/Desktop/raspberry-pico/SDK/pico-extras
apt install cmake gcc-arm-none-eabi gcc g++
apt install gdb-multiarch automake autoconf build-essential texinfo libtool libftdi-dev libusb-1.0-0-dev
git clone https://git.aixiao.me/aixiao/IM1253B.git
cd IM1253B
mkdir -p build
cd build
cmake ..
#cmake -DPICO_BOARD=pico_w ..
make
```

Binary file not shown.

Binary file not shown.

BIN
doc/IM-S11测试软件.exe Normal file

Binary file not shown.

BIN
doc/IM1253B RoHS 2.0.pdf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

180
main.c
View File

@@ -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;
@@ -34,7 +93,7 @@ unsigned int chkcrc(unsigned char *buf, unsigned char len)
void read_data(void)
{
static int i = 0;
static int i = 0;
union crcdata {
unsigned int word16;
unsigned char byte[2];
@@ -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);
@@ -77,14 +138,14 @@ void Analysis_data(void)
unsigned char byte[2];
} crcnow;
if (receive_finished == 1) //接收完成
if (receive_finished == 1) // 接收完成
{
receive_finished = 0;
if (Rx_Buffer[0] == Read_ID) //确认 ID 正确
if (Rx_Buffer[0] == Read_ID) // 确认 ID 正确
{
crcnow.word16 = chkcrc(Rx_Buffer, reveive_number - 2); //reveive_number 是接收数据总长度
if ((crcnow.byte[0] == Rx_Buffer[reveive_number - 1]) && (crcnow.byte[1] == Rx_Buffer[reveive_number - 2])) //确认 CRC 校验正确
crcnow.word16 = chkcrc(Rx_Buffer, receive_number - 2); // receive_number 是接收数据总长度
if ((crcnow.byte[0] == Rx_Buffer[receive_number - 1]) && (crcnow.byte[1] == Rx_Buffer[receive_number - 2])) // 确认 CRC 校验正确
{
Voltage_data = (((unsigned long)(Rx_Buffer[3])) << 24) | (((unsigned long)(Rx_Buffer[4])) << 16) | (((unsigned long)(Rx_Buffer[5])) << 8) | Rx_Buffer[6];
Current_data = (((unsigned long)(Rx_Buffer[7])) << 24) | (((unsigned long)(Rx_Buffer[8])) << 16) | (((unsigned long)(Rx_Buffer[9])) << 8) | Rx_Buffer[10];
@@ -92,6 +153,9 @@ void Analysis_data(void)
Energy_data = (((unsigned long)(Rx_Buffer[15])) << 24) | (((unsigned long)(Rx_Buffer[16])) << 16) | (((unsigned long)(Rx_Buffer[17])) << 8) | Rx_Buffer[18];
Pf_data = (((unsigned long)(Rx_Buffer[19])) << 24) | (((unsigned long)(Rx_Buffer[20])) << 16) | (((unsigned long)(Rx_Buffer[21])) << 8) | Rx_Buffer[22];
CO2_data = (((unsigned long)(Rx_Buffer[23])) << 24) | (((unsigned long)(Rx_Buffer[24])) << 16) | (((unsigned long)(Rx_Buffer[25])) << 8) | Rx_Buffer[26];
Temperature_data = (((unsigned long)(Rx_Buffer[27])) << 24) | (((unsigned long)(Rx_Buffer[28])) << 16) | (((unsigned long)(Rx_Buffer[29])) << 8) | Rx_Buffer[30];
Hz_data = (((unsigned long)(Rx_Buffer[31])) << 24) | (((unsigned long)(Rx_Buffer[32])) << 16) | (((unsigned long)(Rx_Buffer[33])) << 8) | Rx_Buffer[34];
}
}
}
@@ -99,63 +163,81 @@ void Analysis_data(void)
void Print_data(void)
{
float voltage_value = (float)Voltage_data / 10000.0;
float voltage_value = (float)Voltage_data * 0.0001;
printf("电压: %.2f V\n", voltage_value);
float current_data = (float)Current_data / 10000.0;
float current_data = (float)Current_data * 0.0001;
printf("电流: %.2f A\n", current_data);
float power_data = (float)Power_data / 10000.0;
float power_data = (float)Power_data * 0.0001;
printf("功率: %.2f W\n", power_data);
float energy_data = (float)Energy_data / 10000.0;
float energy_data = (float)Energy_data * 0.0001;
printf("电能: %.2f KWH\n", energy_data);
float pf_data = (float)Pf_data / 10000.0;
float pf_data = (float)Pf_data * 0.001;
printf("功率因数: %.2f \n", pf_data);
float cO2_data = (float)CO2_data / 10000.0;
float cO2_data = (float)CO2_data * 0.0001;
printf("二氧化碳: %.2f KG\n", cO2_data);
return ;
printf("温度: %.2f ℃\n", (float)Temperature_data * 0.01);
printf("频率: %.2f HZ\n", (float)Hz_data * 0.01);
return;
}
// 电能清零
void Electric_energy_(int sec)
{
uint8_t RETURN_DATA[8] = { 0 };
uint8_t ELE_ZRRO[13] = { 0x01, 0x10, 0x00, 0x4B, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x2C };
// 加入从开机算起60秒后
if (sec >= 3) {
printf("电能清零\n");
uart_write_blocking(UART0, ELE_ZRRO, 13);
sleep_ms(10);
uart_read_blocking(UART0, RETURN_DATA, 8);
for (int i = 0; i <= 8 - 1; i++) {
printf("0x%X ", RETURN_DATA[i]);
}
printf("\n");
}
return;
}
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
// RX[8]:01 10 00 4B 00 02 31 DE
// 读取 TX[8]:00 03 00 01 00 04 14 18
// RX[13]:01 03 08 02 35 01 08 41 30 01 05 44 BD (直流模块)
// 设置 TX[11]:00 10 00 04 00 01 02 01 05 6B D7
// RX[8]:01 10 00 04 00 01 40 08
*/
// 官方软件内部按钮发送的数据
// 电能清零 TX[13]:01 10 00 4B 00 02 04 00 00 00 00 B6 2C
// RX[8]:01 10 00 4B 00 02 31 DE
// 读取 TX[8]:00 03 00 01 00 04 14 18
// RX[13]:01 03 08 02 35 01 08 41 30 01 05 44 BD (直流模块)
// 设置 TX[11]:00 10 00 04 00 01 02 01 05 6B D7
// RX[8]:01 10 00 04 00 01 40 08
*/
// 发送
read_enable = 1;
read_data();
sleep_ms(10);
// 发送完成后接收数据并处理
reveive_number = 37;
receive_number = 37;
receive_finished = 1;
Analysis_data();
// 打印原始十六进制数据
for (i=0; i <= 37 - 1; i++) {
for (i = 0; i <= 37 - 1; i++) {
printf("0x%X ", Rx_Buffer[i]);
}
printf("\n");
@@ -171,23 +253,31 @@ int main(void)
stdio_init_all();
sleep_ms(1000);
set_sys_clock_khz(250000, true);
// 启动看门狗, 程序如果有阻塞或者程序逻辑错误重启
if (watchdog_caused_reboot()) { // 判断是否从看门狗启动或者正常启动
if (watchdog_caused_reboot()) { // 判断是否从看门狗启动或者正常启动
printf("Rebooted by Watchdog!\n");
} else {
printf("Clean boot\n");
}
watchdog_enable(8300, 1); // 8秒检测是否重新加载看门狗计数器. (不更新计数器则重启硬件, 最高8秒(8秒后不喂狗硬件重启))
watchdog_enable(8300, 1); // 8秒检测是否重新加载看门狗计数器. (不更新计数器则重启硬件, 最高8秒(8秒后不喂狗硬件重启))
watchdog_start_tick(12);
printf("IM1253B module\n");
sec = 0;
printf("IM1253B Module\n");
IM1253B_INIT();
while (1) {
watchdog_update(); // 喂狗
watchdog_update(); // 喂狗
IM1253B();
printf("\n");
// 电能清零
sec++;
Electric_energy_(sec);
sleep_ms(2000);
}

18
main.h
View File

@@ -14,20 +14,31 @@
#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];
unsigned char read_enable, receive_finished, reveive_number;
unsigned long Voltage_data, Current_data, Power_data, Energy_data, Pf_data, CO2_data;
unsigned char read_enable, receive_finished, receive_number;
unsigned long Voltage_data, Current_data, Power_data, Energy_data, Pf_data, CO2_data, Temperature_data, Hz_data;
int sec;
unsigned int calccrc(unsigned char crcbuf, unsigned int crc);
unsigned int chkcrc(unsigned char *buf, unsigned char len);
@@ -36,5 +47,4 @@ void Analysis_data(void);
void Print_data(void);
static uint16_t IM1253B(void);
#endif

94
uart_rx.pio Normal file
View File

@@ -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;
}
%}

130
uart_rx.pio.h Normal file
View File

@@ -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

61
uart_tx.pio Normal file
View File

@@ -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++);
}
%}

78
uart_tx.pio.h Normal file
View File

@@ -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