8000 esp32software serial @chenjunhuan by ywz978020607 · Pull Request #8829 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

esp32software serial @chenjunhuan #8829

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified docs/conf.py
100755 → 100644
Empty file.
Empty file modified lib/mbedtls_errors/do-esp32.sh
100755 → 100644
Empty file.
Empty file modified lib/mbedtls_errors/do-mp.sh
100755 → 100644
Empty file.
Empty file modified lib/mbedtls_errors/do-test.sh
100755 → 100644
Empty file.
1 change: 1 addition & 0 deletions ports/esp32/main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ set(MICROPY_SOURCE_PORT
${PROJECT_DIR}/network_wlan.c
${PROJECT_DIR}/mpnimbleport.c
${PROJECT_DIR}/modsocket.c
${PROJECT_DIR}/modserial.c
${PROJECT_DIR}/modesp.c
${PROJECT_DIR}/esp32_nvs.c
${PROJECT_DIR}/esp32_partition.c
Expand Down
123 changes: 123 additions & 0 deletions ports/esp32/modserial.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
Github: junhuanchen
Copyright (c) 2018 Juwan
Licensed under the MIT license:
http://www.opensource.org/licenses/mit-license.php
*/

#include "sw_serial.h"

#include "py/runtime.h"
#include "py/mperrno.h"
#include "py/mphal.h"
#include "py/nlr.h"

STATIC mp_obj_t serial_initialize() {
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(serial_initialize_obj, serial_initialize);

STATIC mp_obj_t serial_new(size_t n_args, const mp_obj_t *args) {
if (n_args == 4) {
mp_obj_t TxPin = args[0], RxPin = args[1], Inverse = args[2], buffSize = args[3];

/*
if (RxPin != XX) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception,
"RxPin(arg 0) %d ", mp_obj_get_int(RxPin)));
}
*/

SwSerial *self = sw_new(mp_obj_get_int(TxPin), mp_obj_get_int(RxPin), mp_obj_get_int(Inverse), mp_obj_get_int(buffSize));
// printf("%d %d %d %d\n", mp_obj_get_int(TxPin), mp_obj_get_int(RxPin), mp_obj_get_int(Inverse), mp_obj_get_int(buffSize));
if (self != NULL) {
// sw_open(self, 115200);
// sw_stop(self);
return MP_OBJ_FROM_PTR(self);
}
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(serial_new_obj, 0, 4, serial_new);

STATIC mp_obj_t serial_del(mp_obj_t self) {
SwSerial *tmp = (SwSerial *)self;
sw_del(tmp);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(serial_del_obj, serial_del);

STATIC mp_obj_t serial_write(mp_obj_t self, mp_obj_t data) {
SwSerial *tmp = (SwSerial *)self;

// printf("write %d \n", (uint8_t)mp_obj_get_int(data));

sw_write(tmp, (uint8_t)mp_obj_get_int(data));

return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(serial_write_obj, serial_write);

STATIC mp_obj_t serial_read(mp_obj_t self) {
SwSerial *tmp = (SwSerial *)self;

int res = sw_read(tmp);

// printf("read %d \n", (uint8_t)res);

return mp_obj_new_int(res);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(serial_read_obj, serial_read);

STATIC mp_obj_t serial_any(mp_obj_t self) {
SwSerial *tmp = (SwSerial *)self;

int res = sw_any(tmp);

if (res > 0)
{
return mp_obj_new_int(res);
}

return mp_obj_new_int(0);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(serial_any_obj, serial_any);

STATIC mp_obj_t serial_stop(mp_obj_t self) {
SwSerial *tmp = (SwSerial *)self;
return mp_obj_new_int(sw_stop(tmp));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(serial_stop_obj, serial_stop);

STATIC mp_obj_t serial_open(mp_obj_t self, mp_obj_t baudRate) {
SwSerial *tmp = (SwSerial *)self;
esp_err_t res = sw_open(tmp, mp_obj_get_int(baudRate));
return mp_obj_new_int(res);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(serial_open_obj, serial_open);

STATIC const mp_rom_map_elem_t serial_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_serial) },
{ MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&serial_initialize_obj) },

{ MP_ROM_QSTR(MP_QSTR_new), MP_ROM_PTR(&serial_new_obj) },
{ MP_ROM_QSTR(MP_QSTR_del), MP_ROM_PTR(&serial_del_obj) },
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&serial_open_obj) },
{ MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&serial_stop_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&serial_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&serial_read_obj) },
{ MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&serial_any_obj) },

{ MP_ROM_QSTR(MP_QSTR_EOF), MP_ROM_INT((mp_int_t)SW_EOF)},
};

STATIC MP_DEFINE_CONST_DICT(serial_module_globals, serial_module_globals_table);

const mp_obj_module_t serial_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&serial_module_globals,
};

// Note: This port doesn't define MICROPY_PY_NETWORK so this will not conflict
// with the common implementation provided by extmod/modnetwork.c.
MP_REGISTER_MODULE(MP_QSTR_serial, serial_module);
259 changes: 259 additions & 0 deletions ports/esp32/sw_serial.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
/*
Github: junhuanchen
Copyright (c) 2018 Juwan
Licensed under the MIT license:
http://www.opensource.org/licenses/mit-license.php
*/

#include <inttypes.h>

#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/portmacro.h>

#include <esp_clk.h>
#include <driver/gpio.h>
#include <soc/cpu.h>

#define SW_EOF -1

typedef struct sw_serial
{
gpio_num_t rxPin, txPin;
uint32_t buffSize, bitTime, rx_start_time, rx_end_time;
bool invert, overflow;
volatile uint32_t inPos, outPos;
uint8_t *buffer;
} SwSerial;

SwSerial *sw_new(gpio_num_t Tx, gpio_num_t Rx, bool Inverse, int buffSize)
{
SwSerial *tmp = (SwSerial *)malloc(sizeof(SwSerial));

if (NULL != tmp)
{
tmp->invert = Inverse;
tmp->overflow = false;
tmp->inPos = tmp->outPos = 0;
tmp->buffSize = buffSize;
tmp->buffer = (uint8_t *)malloc(buffSize);
if (NULL != tmp->buffer)
{
tmp->rxPin = Rx;
gpio_pad_select_gpio(Rx);
gpio_set_direction(Rx, GPIO_MODE_INPUT);

tmp->txPin = Tx;
gpio_pad_select_gpio(Tx);
gpio_set_direction(Tx, GPIO_MODE_OUTPUT);

// For the TTL level of positive logic, the starting bit is the low level of one bit time.
gpio_set_level(Tx, !Inverse);
// Too short leads to sticky bags
// One byte of time 9600 104us * 10 115200 18us
vTaskDelay(2 / portTICK_RATE_MS);

return tmp;
}
free(tmp), tmp = NULL;
}

return tmp;
}

void sw_del(SwSerial *self)
{
if (NULL != self->buffer)
{
free(self->buffer);
}

free(self);
}

uint32_t getCycleCount()
{
return esp_cpu_get_ccount();
}

#define WaitBitTime(wait) \
for (uint32_t start = getCycleCount(); getCycleCount() - start < wait;)

// The first byte will wrong, after normal
static void IRAM_ATTR sw_rx_handler(void *args)
{
SwSerial *self = (SwSerial *)args;

uint8_t rec = 0;

portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&mux);

// (self->invert) flag invert set Start 1 And Stop 0 invert
// But myself not need, so need extra added by yourself

// Wait Start Bit To Start
WaitBitTime(self->rx_start_time);
if (0 == gpio_get_level(self->rxPin))
{
for (uint8_t i = 0; i != 8; i++)
{
rec >>= 1;
WaitBitTime(self->bitTime);
if (gpio_get_level(self->rxPin))
{
rec |= 0x80;
}
}
// Wait Start Bit To End
WaitBitTime(self->rx_end_time);
if (1 == gpio_get_level(self->rxPin))
{
// Stop bit Allow Into RecvBuffer
// Store the received value in the buffer unless we have an overflow
int next = (self->inPos + 1) % self->buffSize;
if (next != self->outPos)
{
self->buffer[self->inPos] = (self->invert) ? ~rec : rec;
self->inPos = next;
}
else
{
self->overflow = true;
}
}
}

portEXIT_CRITICAL(&mux);
// Must clear this bit in the interrupt register,
// it gets set even when interrupts are disabled

// Esp32 GPIO.status_w1tc interrupt auto recovery
}

esp_err_t sw_enableRx(SwSerial *self, bool State)
{
esp_err_t error = ESP_OK;
if (State)
{
gpio_set_intr_type(self->rxPin, (self->invert) ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE);
gpio_install_isr_service(0);
error = gpio_isr_handler_add(self->rxPin, sw_rx_handler, (void*)self);

}
else
{
error = gpio_isr_handler_remove(self->rxPin);
gpio_uninstall_isr_service();
}

return error;
}

int sw_write(SwSerial *self, uint8_t byte)
{
if (self->invert)
{
byte = ~byte;
}

// Disable interrupts in order to get a clean transmit
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&mux);

// create tx interrupts to start bit.
gpio_set_level(self->txPin, 1), gpio_set_level(self->txPin, 0);

WaitBitTime(self->bitTime);

for (uint8_t i = 0; i != 8; i++)
{
gpio_set_level(self->txPin, (byte & 1) ? 1 : 0);
WaitBitTime(self->bitTime);

byte >>= 1;
}
< F987 /td>
// Stop bit
gpio_set_level(self->txPin, 1);
WaitBitTime(self->bitTime);

// re-enable interrupts
portEXIT_CRITICAL(&mux);

return 1;
}

int sw_read(SwSerial *self)
{
if (self->inPos != self->outPos)
{
uint8_t ch = self->buffer[self->outPos];
self->outPos = (self->outPos + 1) % self->buffSize;
return ch;
}
return -1;
}

// suggest max datalen <= 256 and baudRate <= 115200
esp_err_t sw_open(SwSerial *self, uint32_t baudRate)
{
// The oscilloscope told me
self->bitTime = (esp_clk_cpu_freq() / baudRate);

// Rx bit Timing Settings
switch (baudRate)
{
case 115200:
self->rx_start_time = (self->bitTime / 256);
self->rx_end_time = (self->bitTime * 127 / 256);
break;

case 9600:
self->rx_start_time = (self->bitTime / 9);
self->rx_end_time = (self->bitTime * 8 / 9);
break;

default: // tested 57600 len 256
self->rx_start_time = (self->bitTime / 9);
self->rx_end_time = (self->bitTime * 8 / 9);
break;
}

// printf("sw_open %u %d\n", self->rx_start_time, self->rx_end_time);

sw_write(self, 0x00); // Initialization uart link

return sw_enableRx(self, true);
}

esp_err_t sw_stop(SwSerial *self)
{
return sw_enableRx(self, false);
}

int sw_any(SwSerial *self)
{
int avail = self->inPos - self->outPos;
return (avail < 0) ? avail + self->buffSize : avail;
}

void sw_flush(SwSerial *self)
{
self->inPos = self->outPos = 0;
self->overflow = false;
}

bool sw_overflow(SwSerial *self)
{
return self->overflow;
}

int sw_peek(SwSerial *self)
{
if (self->inPos != self->outPos)
{
return self->buffer[self->outPos];
}
return -1;
}
Empty file modified ports/javascript/node_run.sh
100755 → 100644
Empty file.
Empty file modified ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
100755 → 100644
Empty file.
Empty file modified
Empty file.
Empty file modified ports/nrf/drivers/bluetooth/download_ble_stack.sh
100755 → 100644
Empty file.
Empty file modified ports/stm32/autoflash
100755 → 100644
Empty file.
Empty file modified ports/stm32/boards/NUCLEO_L432KC/stm32l4xx_hal_conf.h
100755 → 100644
Empty file.
Empty file modified ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h
100755 → 100644
Empty file.
Empty file modified ports/stm32/boards/NUCLEO_WB55/rfcore_makefirmware.py
100755 → 100644
Empty file.
Empty file modified ports/stm32/boards/make-pins.py
100755 → 100644
Empty file.
Empty file modified ports/stm32/mboot/Makefile
100755 → 100644
Empty file.
Empty file modified ports/teensy/add-memzip.sh
100755 → 100644
Empty file.
Empty file modified ports/teensy/make-pins.py
100755 → 100644
Empty file.
Empty file modified ports/zephyr/make-bin-testsuite
100755 → 100644
Empty file.
Empty file modified shared/memzip/make-memzip.py
100755 → 100644
Empty file.
Empty file modified tests/run-internalbench.py
100755 → 100644
Empty file.
Empty file modified tests/run-multitests.py
100755 → 100644
Empty file.
Empty file modified tests/run-natmodtests.py
100755 → 100644
Empty file.
Empty file modified tests/run-perfbench.py
100755 → 100644
Empty file.
Empty file modified tests/run-tests-exp.sh
100755 → 100644
Empty file.
Empty file modified tests/run-tests.py
100755 → 100644
Empty file.
Empty file modified tools/autobuild/autobuild.sh
100755 → 100644
Empty file.
Empty file modified tools/autobuild/build-boards.sh
100755 → 100644
Empty file.
Empty file modified tools/autobuild/build-cc3200-latest.sh
100755 → 100644
Empty file.
Empty file modified tools/autobuild/build-downloads.py
100755 → 100644
Empty file.
Empty file modified tools/autobuild/build-esp8266-latest.sh
100755 → 100644
Empty file.
Empty file modified tools/autobuild/build-stm32-extra.sh
100755 → 100644
Empty file.
Empty file modified tools/autobuild/remove_old_firmware.py
100755 → 100644
Empty file.
Empty file modified tools/cc1
100755 → 100644
Empty file.
Empty file modified tools/ci.sh
100755 → 100644
Empty file.
Empty file modified tools/codeformat.py
100755 → 100644
Empty file.
Empty file modified tools/codestats.sh
100755 → 100644
Empty file.
Empty file modified tools/dfu.py
100755 → 100644
Empty file.
Empty file modified tools/gen-changelog.sh
100755 → 100644
Empty file.
Empty file modified tools/metrics.py
100755 → 100644
Empty file.
Empty file modified tools/mpremote/mpremote.py
100755 → 100644
Empty file.
Empty file modified tools/mpy-tool.py
100755 → 100644
10000
Empty file.
Empty file modified tools/mpy_bin2res.py
100755 → 100644
Empty file.
Empty file modified tools/mpy_cross_all.py
100755 → 100644
Empty file.
Empty file modified tools/mpy_ld.py
100755 → 100644
Empty file.
Empty file modified tools/pyboard.py
100755 → 100644
Empty file.
Empty file modified tools/pydfu.py
100755 → 100644
Empty file.
Empty file modified tools/tinytest-codegen.py
100755 → 100644
Empty file.
Empty file modified tools/verifygitlog.py
100755 → 100644
Empty file.
0