<:Nami2:939038794794020874>

This commit is contained in:
ClaraCrazy
2023-07-17 16:46:04 +02:00
parent 315691b13c
commit bcb8468e27
73 changed files with 29 additions and 29 deletions

View File

@@ -0,0 +1,181 @@
/* Copyright 2020-2023 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "esp32_port.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "esp_timer.h"
#include "esp_log.h"
#include "esp_idf_version.h"
#include <unistd.h>
#ifdef SERIAL_FLASHER_DEBUG_TRACE
static void transfer_debug_print(const uint8_t *data, uint16_t size, bool write)
{
static bool write_prev = false;
if (write_prev != write) {
write_prev = write;
printf("\n--- %s ---\n", write ? "WRITE" : "READ");
}
for (uint32_t i = 0; i < size; i++) {
printf("%02x ", data[i]);
}
}
#endif
static int64_t s_time_end;
static int32_t s_uart_port;
static int32_t s_reset_trigger_pin;
static int32_t s_gpio0_trigger_pin;
esp_loader_error_t loader_port_esp32_init(const loader_esp32_config_t *config)
{
s_uart_port = config->uart_port;
s_reset_trigger_pin = config->reset_trigger_pin;
s_gpio0_trigger_pin = config->gpio0_trigger_pin;
// Initialize UART
uart_config_t uart_config = {
.baud_rate = config->baud_rate,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
.source_clk = UART_SCLK_DEFAULT,
#endif
};
int rx_buffer_size = config->rx_buffer_size ? config->rx_buffer_size : 400;
int tx_buffer_size = config->tx_buffer_size ? config->tx_buffer_size : 400;
QueueHandle_t *uart_queue = config->uart_queue ? config->uart_queue : NULL;
int queue_size = config->queue_size ? config->queue_size : 0;
if ( uart_param_config(s_uart_port, &uart_config) != ESP_OK ) {
return ESP_LOADER_ERROR_FAIL;
}
if ( uart_set_pin(s_uart_port, config->uart_tx_pin, config->uart_rx_pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE) != ESP_OK ) {
return ESP_LOADER_ERROR_FAIL;
}
if ( uart_driver_install(s_uart_port, rx_buffer_size, tx_buffer_size, queue_size, uart_queue, 0) != ESP_OK ) {
return ESP_LOADER_ERROR_FAIL;
}
// Initialize boot pin selection pins
gpio_reset_pin(s_reset_trigger_pin);
gpio_set_pull_mode(s_reset_trigger_pin, GPIO_PULLUP_ONLY);
gpio_set_direction(s_reset_trigger_pin, GPIO_MODE_OUTPUT);
gpio_reset_pin(s_gpio0_trigger_pin);
gpio_set_pull_mode(s_gpio0_trigger_pin, GPIO_PULLUP_ONLY);
gpio_set_direction(s_gpio0_trigger_pin, GPIO_MODE_OUTPUT);
return ESP_LOADER_SUCCESS;
}
void loader_port_esp32_deinit(void)
{
uart_driver_delete(s_uart_port);
}
esp_loader_error_t loader_port_write(const uint8_t *data, uint16_t size, uint32_t timeout)
{
uart_write_bytes(s_uart_port, (const char *)data, size);
esp_err_t err = uart_wait_tx_done(s_uart_port, pdMS_TO_TICKS(timeout));
if (err == ESP_OK) {
#ifdef SERIAL_FLASHER_DEBUG_TRACE
transfer_debug_print(data, size, true);
#endif
return ESP_LOADER_SUCCESS;
} else if (err == ESP_ERR_TIMEOUT) {
return ESP_LOADER_ERROR_TIMEOUT;
} else {
return ESP_LOADER_ERROR_FAIL;
}
}
esp_loader_error_t loader_port_read(uint8_t *data, uint16_t size, uint32_t timeout)
{
int read = uart_read_bytes(s_uart_port, data, size, pdMS_TO_TICKS(timeout));
if (read < 0) {
return ESP_LOADER_ERROR_FAIL;
} else if (read < size) {
#ifdef SERIAL_FLASHER_DEBUG_TRACE
transfer_debug_print(data, read, false);
#endif
return ESP_LOADER_ERROR_TIMEOUT;
} else {
#ifdef SERIAL_FLASHER_DEBUG_TRACE
transfer_debug_print(data, read, false);
#endif
return ESP_LOADER_SUCCESS;
}
}
// Set GPIO0 LOW, then
// assert reset pin for 50 milliseconds.
void loader_port_enter_bootloader(void)
{
gpio_set_level(s_gpio0_trigger_pin, 0);
loader_port_reset_target();
loader_port_delay_ms(SERIAL_FLASHER_BOOT_HOLD_TIME_MS);
gpio_set_level(s_gpio0_trigger_pin, 1);
}
void loader_port_reset_target(void)
{
gpio_set_level(s_reset_trigger_pin, 0);
loader_port_delay_ms(SERIAL_FLASHER_RESET_HOLD_TIME_MS);
gpio_set_level(s_reset_trigger_pin, 1);
}
void loader_port_delay_ms(uint32_t ms)
{
usleep(ms * 1000);
}
void loader_port_start_timer(uint32_t ms)
{
s_time_end = esp_timer_get_time() + ms * 1000;
}
uint32_t loader_port_remaining_time(void)
{
int64_t remaining = (s_time_end - esp_timer_get_time()) / 1000;
return (remaining > 0) ? (uint32_t)remaining : 0;
}
void loader_port_debug_print(const char *str)
{
printf("DEBUG: %s\n", str);
}
esp_loader_error_t loader_port_change_transmission_rate(uint32_t baudrate)
{
esp_err_t err = uart_set_baudrate(s_uart_port, baudrate);
return (err == ESP_OK) ? ESP_LOADER_SUCCESS : ESP_LOADER_ERROR_FAIL;
}

View File

@@ -0,0 +1,59 @@
/* Copyright 2020-2023 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "esp_loader_io.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
uint32_t baud_rate; /*!< Initial baud rate, can be changed later */
uint32_t uart_port; /*!< UART port */
uint32_t uart_rx_pin; /*!< This pin will be configured as UART Rx pin */
uint32_t uart_tx_pin; /*!< This pin will be configured as UART Tx pin */
uint32_t reset_trigger_pin; /*!< This pin will be used to reset target chip */
uint32_t gpio0_trigger_pin; /*!< This pin will be used to toggle set IO0 of target chip */
uint32_t rx_buffer_size; /*!< Set to zero for default RX buffer size */
uint32_t tx_buffer_size; /*!< Set to zero for default TX buffer size */
uint32_t queue_size; /*!< Set to zero for default UART queue size */
QueueHandle_t *uart_queue; /*!< Set to NULL, if UART queue handle is not
necessary. Otherwise, it will be assigned here */
} loader_esp32_config_t;
/**
* @brief Initializes serial interface.
*
* @param baud_rate[in] Communication speed.
*
* @return
* - ESP_LOADER_SUCCESS Success
* - ESP_LOADER_ERROR_FAIL Initialization failure
*/
esp_loader_error_t loader_port_esp32_init(const loader_esp32_config_t *config);
/**
* @brief Deinitialize serial interface.
*/
void loader_port_esp32_deinit(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,298 @@
/* Copyright 2020-2023 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "esp32_spi_port.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "esp_timer.h"
#include "esp_log.h"
#include "esp_idf_version.h"
#include <unistd.h>
// #define SERIAL_DEBUG_ENABLE
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0)
#define DMA_CHAN SPI_DMA_CH_AUTO
#else
#define DMA_CHAN 1
#endif
#define WORD_ALIGNED(ptr) ((size_t)ptr % sizeof(size_t) == 0)
#ifdef SERIAL_DEBUG_ENABLE
static void dec_to_hex_str(const uint8_t dec, uint8_t hex_str[3])
{
static const uint8_t dec_to_hex[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
hex_str[0] = dec_to_hex[dec >> 4];
hex_str[1] = dec_to_hex[dec & 0xF];
hex_str[2] = '\0';
}
static void serial_debug_print(const uint8_t *data, uint16_t size, bool write)
{
static bool write_prev = false;
uint8_t hex_str[3];
if(write_prev != write) {
write_prev = write;
printf("\n--- %s ---\n", write ? "WRITE" : "READ");
}
for(uint32_t i = 0; i < size; i++) {
dec_to_hex_str(data[i], hex_str);
printf("%s ", hex_str);
}
}
#else
static void serial_debug_print(const uint8_t *data, uint16_t size, bool write) { }
#endif
static spi_host_device_t s_spi_bus;
static spi_bus_config_t s_spi_config;
static spi_device_handle_t s_device_h;
static spi_device_interface_config_t s_device_config;
static int64_t s_time_end;
static uint32_t s_reset_trigger_pin;
static uint32_t s_strap_bit0_pin;
static uint32_t s_strap_bit1_pin;
static uint32_t s_strap_bit2_pin;
static uint32_t s_strap_bit3_pin;
static uint32_t s_spi_cs_pin;
esp_loader_error_t loader_port_esp32_spi_init(const loader_esp32_spi_config_t *config)
{
/* Initialize the global static variables*/
s_spi_bus = config->spi_bus;
s_reset_trigger_pin = config->reset_trigger_pin;
s_strap_bit0_pin = config->strap_bit0_pin;
s_strap_bit1_pin = config->strap_bit1_pin;
s_strap_bit2_pin = config->strap_bit2_pin;
s_strap_bit3_pin = config->strap_bit3_pin;
s_spi_cs_pin = config->spi_cs_pin;
/* Configure and initialize the SPI bus*/
s_spi_config.mosi_io_num = config->spi_mosi_pin;
s_spi_config.miso_io_num = config->spi_miso_pin;
s_spi_config.sclk_io_num = config->spi_clk_pin;
s_spi_config.quadwp_io_num = config->spi_quadwp_pin;
s_spi_config.quadhd_io_num = config->spi_quadhd_pin;
s_spi_config.max_transfer_sz = 4096 * 4;
if (spi_bus_initialize(s_spi_bus, &s_spi_config, DMA_CHAN) != ESP_OK) {
return ESP_LOADER_ERROR_FAIL;
}
/* Configure and add the device */
s_device_config.clock_speed_hz = config->frequency;
s_device_config.spics_io_num = -1; /* We're using the chip select pin as GPIO as we need to
chain multiple transactions with CS pulled down */
s_device_config.flags = SPI_DEVICE_HALFDUPLEX;
s_device_config.queue_size = 16;
if (spi_bus_add_device(s_spi_bus, &s_device_config, &s_device_h) != ESP_OK) {
return ESP_LOADER_ERROR_FAIL;
}
/* Initialize the pins except for the strapping ones */
gpio_reset_pin(s_reset_trigger_pin);
gpio_set_pull_mode(s_reset_trigger_pin, GPIO_PULLUP_ONLY);
gpio_set_direction(s_reset_trigger_pin, GPIO_MODE_OUTPUT);
gpio_set_level(s_reset_trigger_pin, 1);
gpio_reset_pin(s_spi_cs_pin);
gpio_set_pull_mode(s_spi_cs_pin, GPIO_PULLUP_ONLY);
gpio_set_direction(s_spi_cs_pin, GPIO_MODE_OUTPUT);
gpio_set_level(s_spi_cs_pin, 1);
return ESP_LOADER_SUCCESS;
}
void loader_port_esp32_spi_deinit(void)
{
gpio_reset_pin(s_reset_trigger_pin);
gpio_reset_pin(s_spi_cs_pin);
spi_bus_remove_device(s_device_h);
spi_bus_free(s_spi_bus);
}
void loader_port_spi_set_cs(const uint32_t level) {
gpio_set_level(s_spi_cs_pin, level);
}
esp_loader_error_t loader_port_write(const uint8_t *data, const uint16_t size, const uint32_t timeout)
{
/* Due to the fact that the SPI driver uses DMA for larger transfers,
and the DMA requirements, the buffer must be word aligned */
if (data == NULL || !WORD_ALIGNED(data)) {
return ESP_LOADER_ERROR_INVALID_PARAM;
}
serial_debug_print(data, size, true);
spi_transaction_t transaction = {
.tx_buffer = data,
.rx_buffer = NULL,
.length = size * 8U,
.rxlength = 0,
};
esp_err_t err = spi_device_transmit(s_device_h, &transaction);
if (err == ESP_OK) {
serial_debug_print(data, size, false);
return ESP_LOADER_SUCCESS;
} else if (err == ESP_ERR_TIMEOUT) {
return ESP_LOADER_ERROR_TIMEOUT;
} else {
return ESP_LOADER_ERROR_FAIL;
}
}
esp_loader_error_t loader_port_read(uint8_t *data, const uint16_t size, const uint32_t timeout)
{
/* Due to the fact that the SPI driver uses DMA for larger transfers,
and the DMA requirements, the buffer must be word aligned */
if (data == NULL || !WORD_ALIGNED(data)) {
return ESP_LOADER_ERROR_INVALID_PARAM;
}
serial_debug_print(data, size, true);
spi_transaction_t transaction = {
.tx_buffer = NULL,
.rx_buffer = data,
.rxlength = size * 8,
};
esp_err_t err = spi_device_transmit(s_device_h, &transaction);
if (err == ESP_OK) {
serial_debug_print(data, size, false);
return ESP_LOADER_SUCCESS;
} else if (err == ESP_ERR_TIMEOUT) {
return ESP_LOADER_ERROR_TIMEOUT;
} else {
return ESP_LOADER_ERROR_FAIL;
}
}
void loader_port_enter_bootloader(void)
{
/*
We have to initialize the GPIO pins for the target strapping pins here,
as they may overlap with target SPI pins.
For instance in the case of ESP32C3 MISO and strapping bit 0 pins overlap.
*/
spi_bus_remove_device(s_device_h);
spi_bus_free(s_spi_bus);
gpio_reset_pin(s_strap_bit0_pin);
gpio_set_pull_mode(s_strap_bit0_pin, GPIO_PULLUP_ONLY);
gpio_set_direction(s_strap_bit0_pin, GPIO_MODE_OUTPUT);
gpio_reset_pin(s_strap_bit1_pin);
gpio_set_pull_mode(s_strap_bit1_pin, GPIO_PULLUP_ONLY);
gpio_set_direction(s_strap_bit1_pin, GPIO_MODE_OUTPUT);
gpio_reset_pin(s_strap_bit2_pin);
gpio_set_pull_mode(s_strap_bit2_pin, GPIO_PULLUP_ONLY);
gpio_set_direction(s_strap_bit2_pin, GPIO_MODE_OUTPUT);
gpio_reset_pin(s_strap_bit3_pin);
gpio_set_pull_mode(s_strap_bit3_pin, GPIO_PULLUP_ONLY);
gpio_set_direction(s_strap_bit3_pin, GPIO_MODE_OUTPUT);
/* Set the strapping pins and perform the reset sequence */
gpio_set_level(s_strap_bit0_pin, 1);
gpio_set_level(s_strap_bit1_pin, 0);
gpio_set_level(s_strap_bit2_pin, 0);
gpio_set_level(s_strap_bit3_pin, 0);
loader_port_reset_target();
loader_port_delay_ms(SERIAL_FLASHER_BOOT_HOLD_TIME_MS);
gpio_set_level(s_strap_bit3_pin, 1);
gpio_set_level(s_strap_bit0_pin, 0);
/* Disable the strapping pins so they can be used by the slave later */
gpio_reset_pin(s_strap_bit0_pin);
gpio_reset_pin(s_strap_bit1_pin);
gpio_reset_pin(s_strap_bit2_pin);
gpio_reset_pin(s_strap_bit3_pin);
/* Restore the SPI bus pins */
spi_bus_initialize(s_spi_bus, &s_spi_config, DMA_CHAN);
spi_bus_add_device(s_spi_bus, &s_device_config, &s_device_h);
}
void loader_port_reset_target(void)
{
gpio_set_level(s_reset_trigger_pin, 0);
loader_port_delay_ms(SERIAL_FLASHER_RESET_HOLD_TIME_MS);
gpio_set_level(s_reset_trigger_pin, 1);
}
void loader_port_delay_ms(const uint32_t ms)
{
usleep(ms * 1000);
}
void loader_port_start_timer(const uint32_t ms)
{
s_time_end = esp_timer_get_time() + ms * 1000;
}
uint32_t loader_port_remaining_time(void)
{
int64_t remaining = (s_time_end - esp_timer_get_time()) / 1000;
return (remaining > 0) ? (uint32_t)remaining : 0;
}
void loader_port_debug_print(const char *str)
{
printf("DEBUG: %s\n", str);
}
esp_loader_error_t loader_port_change_transmission_rate(const uint32_t frequency)
{
if (spi_bus_remove_device(s_device_h) != ESP_OK) {
return ESP_LOADER_ERROR_FAIL;
}
uint32_t old_frequency = s_device_config.clock_speed_hz;
s_device_config.clock_speed_hz = frequency;
if (spi_bus_add_device(s_spi_bus, &s_device_config, &s_device_h) != ESP_OK) {
s_device_config.clock_speed_hz = old_frequency;
return ESP_LOADER_ERROR_FAIL;
}
return ESP_LOADER_SUCCESS;
}

View File

@@ -0,0 +1,60 @@
/* Copyright 2020-2023 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "esp_loader_io.h"
#include "driver/spi_master.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
spi_host_device_t spi_bus;
uint32_t frequency;
uint32_t spi_clk_pin;
uint32_t spi_miso_pin;
uint32_t spi_mosi_pin;
uint32_t spi_cs_pin;
uint32_t spi_quadwp_pin;
uint32_t spi_quadhd_pin;
uint32_t reset_trigger_pin;
uint32_t strap_bit0_pin;
uint32_t strap_bit1_pin;
uint32_t strap_bit2_pin;
uint32_t strap_bit3_pin;
} loader_esp32_spi_config_t;
/**
* @brief Initializes the SPI interface.
*
* @param config[in] Configuration structure
*
* @return
* - ESP_LOADER_SUCCESS Success
* - ESP_LOADER_ERROR_FAIL Initialization failure
*/
esp_loader_error_t loader_port_esp32_spi_init(const loader_esp32_spi_config_t *config);
/**
* @brief Deinitializes the SPI interface.
*/
void loader_port_esp32_spi_deinit(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,302 @@
/* Copyright 2020-2023 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "esp_loader_io.h"
#include "protocol.h"
#include <pigpio.h>
#include "raspberry_port.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <time.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#ifdef SERIAL_FLASHER_DEBUG_TRACE
static void transfer_debug_print(const uint8_t *data, uint16_t size, bool write)
{
static bool write_prev = false;
if (write_prev != write) {
write_prev = write;
printf("\n--- %s ---\n", write ? "WRITE" : "READ");
}
for (uint32_t i = 0; i < size; i++) {
printf("%02x ", data[i]);
}
}
#endif
static int serial;
static int64_t s_time_end;
static int32_t s_reset_trigger_pin;
static int32_t s_gpio0_trigger_pin;
static speed_t convert_baudrate(int baud)
{
switch (baud) {
case 50: return B50;
case 75: return B75;
case 110: return B110;
case 134: return B134;
case 150: return B150;
case 200: return B200;
case 300: return B300;
case 600: return B600;
case 1200: return B1200;
case 1800: return B1800;
case 2400: return B2400;
case 4800: return B4800;
case 9600: return B9600;
case 19200: return B19200;
case 38400: return B38400;
case 57600: return B57600;
case 115200: return B115200;
case 230400: return B230400;
case 460800: return B460800;
case 500000: return B500000;
case 576000: return B576000;
case 921600: return B921600;
case 1000000: return B1000000;
case 1152000: return B1152000;
case 1500000: return B1500000;
case 2000000: return B2000000;
case 2500000: return B2500000;
case 3000000: return B3000000;
case 3500000: return B3500000;
case 4000000: return B4000000;
default: return -1;
}
}
static int serialOpen (const char *device, uint32_t baudrate)
{
struct termios options;
int status, fd;
if ((fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1) {
printf("Error occured while opening serial port !\n");
return -1 ;
}
fcntl (fd, F_SETFL, O_RDWR) ;
// Get and modify current options:
tcgetattr (fd, &options);
speed_t baud = convert_baudrate(baudrate);
if(baud < 0) {
printf("Invalid baudrate!\n");
return -1;
}
cfmakeraw (&options) ;
cfsetispeed (&options, baud) ;
cfsetospeed (&options, baud) ;
options.c_cflag |= (CLOCAL | CREAD) ;
options.c_cflag &= ~(PARENB | CSTOPB | CSIZE) ;
options.c_cflag |= CS8 ;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;
options.c_oflag &= ~OPOST ;
options.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); // Disable any special handling of received bytes
options.c_cc [VMIN] = 0 ;
options.c_cc [VTIME] = 10 ; // 1 Second
tcsetattr (fd, TCSANOW, &options) ;
ioctl (fd, TIOCMGET, &status);
status |= TIOCM_DTR ;
status |= TIOCM_RTS ;
ioctl (fd, TIOCMSET, &status);
usleep (10000) ; // 10mS
return fd ;
}
static esp_loader_error_t change_baudrate(int file_desc, int baudrate)
{
struct termios options;
speed_t baud = convert_baudrate(baudrate);
if(baud < 0) {
return ESP_LOADER_ERROR_INVALID_PARAM;
}
tcgetattr (file_desc, &options);
cfmakeraw (&options) ;
cfsetispeed (&options, baud);
cfsetospeed (&options, baud);
tcsetattr (file_desc, TCSANOW, &options);
return ESP_LOADER_SUCCESS;
}
static void set_timeout(uint32_t timeout)
{
struct termios options;
timeout /= 100;
timeout = MAX(timeout, 1);
tcgetattr(serial, &options);
options.c_cc[VTIME] = timeout;
tcsetattr(serial, TCSANOW, &options);
}
static esp_loader_error_t read_char(char *c, uint32_t timeout)
{
set_timeout(timeout);
int read_bytes = read(serial, c, 1);
if (read_bytes == 1) {
return ESP_LOADER_SUCCESS;
} else if (read_bytes == 0) {
return ESP_LOADER_ERROR_TIMEOUT;
} else {
return ESP_LOADER_ERROR_FAIL;
}
}
static esp_loader_error_t read_data(char *buffer, uint32_t size)
{
for (int i = 0; i < size; i++) {
uint32_t remaining_time = loader_port_remaining_time();
RETURN_ON_ERROR( read_char(&buffer[i], remaining_time) );
}
return ESP_LOADER_SUCCESS;
}
esp_loader_error_t loader_port_raspberry_init(const loader_raspberry_config_t *config)
{
s_reset_trigger_pin = config->reset_trigger_pin;
s_gpio0_trigger_pin = config->gpio0_trigger_pin;
serial = serialOpen(config->device, config->baudrate);
if (serial < 0) {
printf("Serial port could not be opened!\n");
return ESP_LOADER_ERROR_FAIL;
}
if (gpioInitialise() < 0) {
printf("pigpio initialisation failed\n");
return ESP_LOADER_ERROR_FAIL;
}
gpioSetMode(config->reset_trigger_pin, PI_OUTPUT);
gpioSetMode(config->gpio0_trigger_pin, PI_OUTPUT);
return ESP_LOADER_SUCCESS;
}
esp_loader_error_t loader_port_write(const uint8_t *data, uint16_t size, uint32_t timeout)
{
int written = write(serial, data, size);
if (written < 0) {
return ESP_LOADER_ERROR_FAIL;
} else if (written < size) {
#ifdef SERIAL_FLASHER_DEBUG_TRACE
transfer_debug_print(data, written, true);
#endif
return ESP_LOADER_ERROR_TIMEOUT;
} else {
#ifdef SERIAL_FLASHER_DEBUG_TRACE
transfer_debug_print(data, written, true);
#endif
return ESP_LOADER_SUCCESS;
}
}
esp_loader_error_t loader_port_read(uint8_t *data, uint16_t size, uint32_t timeout)
{
RETURN_ON_ERROR( read_data(data, size) );
#ifdef SERIAL_FLASHER_DEBUG_TRACE
transfer_debug_print(data, size, false);
#endif
return ESP_LOADER_SUCCESS;
}
// Set GPIO0 LOW, then assert reset pin for 50 milliseconds.
void loader_port_enter_bootloader(void)
{
gpioWrite(s_gpio0_trigger_pin, 0);
loader_port_reset_target();
loader_port_delay_ms(SERIAL_FLASHER_BOOT_HOLD_TIME_MS);
gpioWrite(s_gpio0_trigger_pin, 1);
}
void loader_port_reset_target(void)
{
gpioWrite(s_reset_trigger_pin, 0);
loader_port_delay_ms(SERIAL_FLASHER_RESET_HOLD_TIME_MS);
gpioWrite(s_reset_trigger_pin, 1);
}
void loader_port_delay_ms(uint32_t ms)
{
usleep(ms * 1000);
}
void loader_port_start_timer(uint32_t ms)
{
s_time_end = clock() + (ms * (CLOCKS_PER_SEC / 1000));
}
uint32_t loader_port_remaining_time(void)
{
int64_t remaining = (s_time_end - clock()) / 1000;
return (remaining > 0) ? (uint32_t)remaining : 0;
}
void loader_port_debug_print(const char *str)
{
printf("DEBUG: %s\n", str);
}
esp_loader_error_t loader_port_change_transmission_rate(uint32_t baudrate)
{
return change_baudrate(serial, baudrate);
}

View File

@@ -0,0 +1,36 @@
/* Copyright 2020-2023 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <stdint.h>
#include "esp_loader_io.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
const char *device;
uint32_t baudrate;
uint32_t reset_trigger_pin;
uint32_t gpio0_trigger_pin;
} loader_raspberry_config_t;
esp_loader_error_t loader_port_raspberry_init(const loader_raspberry_config_t *config);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,140 @@
/* Copyright 2020-2023 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/param.h>
#include <stdio.h>
#include "stm32_port.h"
static UART_HandleTypeDef *uart;
static GPIO_TypeDef* gpio_port_io0, *gpio_port_rst;
static uint16_t gpio_num_io0, gpio_num_rst;
#ifdef SERIAL_FLASHER_DEBUG_TRACE
static void transfer_debug_print(const uint8_t *data, uint16_t size, bool write)
{
static bool write_prev = false;
if (write_prev != write) {
write_prev = write;
printf("\n--- %s ---\n", write ? "WRITE" : "READ");
}
for (uint32_t i = 0; i < size; i++) {
printf("%02x ", data[i]);
}
}
#endif
static uint32_t s_time_end;
esp_loader_error_t loader_port_write(const uint8_t *data, uint16_t size, uint32_t timeout)
{
HAL_StatusTypeDef err = HAL_UART_Transmit(uart, (uint8_t *)data, size, timeout);
if (err == HAL_OK) {
#ifdef SERIAL_FLASHER_DEBUG_TRACE
transfer_debug_print(data, size, true);
#endif
return ESP_LOADER_SUCCESS;
} else if (err == HAL_TIMEOUT) {
return ESP_LOADER_ERROR_TIMEOUT;
} else {
return ESP_LOADER_ERROR_FAIL;
}
}
esp_loader_error_t loader_port_read(uint8_t *data, uint16_t size, uint32_t timeout)
{
HAL_StatusTypeDef err = HAL_UART_Receive(uart, data, size, timeout);
if (err == HAL_OK) {
#ifdef SERIAL_FLASHER_DEBUG_TRACE
transfer_debug_print(data, size, false);
#endif
return ESP_LOADER_SUCCESS;
} else if (err == HAL_TIMEOUT) {
return ESP_LOADER_ERROR_TIMEOUT;
} else {
return ESP_LOADER_ERROR_FAIL;
}
}
void loader_port_stm32_init(loader_stm32_config_t *config)
{
uart = config->huart;
gpio_port_io0 = config->port_io0;
gpio_port_rst = config->port_rst;
gpio_num_io0 = config->pin_num_io0;
gpio_num_rst = config->pin_num_rst;
}
// Set GPIO0 LOW, then
// assert reset pin for 100 milliseconds.
void loader_port_enter_bootloader(void)
{
HAL_GPIO_WritePin(gpio_port_io0, gpio_num_io0, GPIO_PIN_RESET);
loader_port_reset_target();
HAL_Delay(SERIAL_FLASHER_BOOT_HOLD_TIME_MS);
HAL_GPIO_WritePin(gpio_port_io0, gpio_num_io0, GPIO_PIN_SET);
}
void loader_port_reset_target(void)
{
HAL_GPIO_WritePin(gpio_port_rst, gpio_num_rst, GPIO_PIN_RESET);
HAL_Delay(SERIAL_FLASHER_RESET_HOLD_TIME_MS);
HAL_GPIO_WritePin(gpio_port_rst, gpio_num_rst, GPIO_PIN_SET);
}
void loader_port_delay_ms(uint32_t ms)
{
HAL_Delay(ms);
}
void loader_port_start_timer(uint32_t ms)
{
s_time_end = HAL_GetTick() + ms;
}
uint32_t loader_port_remaining_time(void)
{
int32_t remaining = s_time_end - HAL_GetTick();
return (remaining > 0) ? (uint32_t)remaining : 0;
}
void loader_port_debug_print(const char *str)
{
printf("DEBUG: %s", str);
}
esp_loader_error_t loader_port_change_transmission_rate(uint32_t baudrate)
{
uart->Init.BaudRate = baudrate;
if( HAL_UART_Init(uart) != HAL_OK ) {
return ESP_LOADER_ERROR_FAIL;
}
return ESP_LOADER_SUCCESS;
}

View File

@@ -0,0 +1,38 @@
/* Copyright 2020-2023 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <stdint.h>
#include "esp_loader_io.h"
#include "stm32f4xx_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
UART_HandleTypeDef *huart;
GPIO_TypeDef *port_io0;
uint16_t pin_num_io0;
GPIO_TypeDef *port_rst;
uint16_t pin_num_rst;
} loader_stm32_config_t;
void loader_port_stm32_init(loader_stm32_config_t *config);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,170 @@
/*
* Copyright (c) 2022 KT-Elektronik, Klaucke und Partner GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "zephyr_port.h"
#include <zephyr/drivers/uart.h>
#include <zephyr/console/tty.h>
static const struct device *uart_dev;
static struct gpio_dt_spec enable_spec;
static struct gpio_dt_spec boot_spec;
static struct tty_serial tty;
static char tty_rx_buf[CONFIG_ESP_SERIAL_FLASHER_UART_BUFSIZE];
static char tty_tx_buf[CONFIG_ESP_SERIAL_FLASHER_UART_BUFSIZE];
#ifdef SERIAL_FLASHER_DEBUG_TRACE
static void transfer_debug_print(const uint8_t *data, uint16_t size, bool write)
{
static bool write_prev = false;
if (write_prev != write) {
write_prev = write;
printk("\n--- %s ---\n", write ? "WRITE" : "READ");
}
for (uint32_t i = 0; i < size; i++) {
printk("%02x ", data[i]);
}
}
#endif
esp_loader_error_t configure_tty()
{
if (tty_init(&tty, uart_dev) < 0 ||
tty_set_rx_buf(&tty, tty_rx_buf, sizeof(tty_rx_buf)) < 0 ||
tty_set_tx_buf(&tty, tty_tx_buf, sizeof(tty_tx_buf)) < 0) {
return ESP_LOADER_ERROR_FAIL;
}
return ESP_LOADER_SUCCESS;
}
esp_loader_error_t loader_port_read(uint8_t *data, const uint16_t size, const uint32_t timeout)
{
if (!device_is_ready(uart_dev) || data == NULL || size == 0) {
return ESP_LOADER_ERROR_FAIL;
}
ssize_t total_read = 0;
ssize_t remaining = size;
tty_set_rx_timeout(&tty, timeout);
while (remaining > 0) {
const uint16_t chunk_size = remaining < CONFIG_ESP_SERIAL_FLASHER_UART_BUFSIZE ?
remaining : CONFIG_ESP_SERIAL_FLASHER_UART_BUFSIZE;
ssize_t read = tty_read(&tty, &data[total_read], chunk_size);
if (read < 0) {
return ESP_LOADER_ERROR_TIMEOUT;
}
#ifdef SERIAL_FLASHER_DEBUG_TRACE
transfer_debug_print(data, read, false);
#endif
total_read += read;
remaining -= read;
}
return ESP_LOADER_SUCCESS;
}
esp_loader_error_t loader_port_write(const uint8_t *data, const uint16_t size, const uint32_t timeout)
{
if (!device_is_ready(uart_dev) || data == NULL || size == 0) {
return ESP_LOADER_ERROR_FAIL;
}
ssize_t total_written = 0;
ssize_t remaining = size;
tty_set_tx_timeout(&tty, timeout);
while (remaining > 0) {
const uint16_t chunk_size = remaining < CONFIG_ESP_SERIAL_FLASHER_UART_BUFSIZE ?
remaining : CONFIG_ESP_SERIAL_FLASHER_UART_BUFSIZE;
ssize_t written = tty_write(&tty, &data[total_written], chunk_size);
if (written < 0) {
return ESP_LOADER_ERROR_TIMEOUT;
}
#ifdef SERIAL_FLASHER_DEBUG_TRACE
transfer_debug_print(data, written, true);
#endif
total_written += written;
remaining -= written;
}
return ESP_LOADER_SUCCESS;
}
esp_loader_error_t loader_port_zephyr_init(const loader_zephyr_config_t *config)
{
uart_dev = config->uart_dev;
enable_spec = config->enable_spec;
boot_spec = config->boot_spec;
return configure_tty();
}
void loader_port_reset_target(void)
{
gpio_pin_set_dt(&enable_spec, false);
loader_port_delay_ms(CONFIG_SERIAL_FLASHER_RESET_HOLD_TIME_MS);
gpio_pin_set_dt(&enable_spec, true);
}
void loader_port_enter_bootloader(void)
{
gpio_pin_set_dt(&boot_spec, false);
loader_port_reset_target();
loader_port_delay_ms(CONFIG_SERIAL_FLASHER_BOOT_HOLD_TIME_MS);
gpio_pin_set_dt(&boot_spec, true);
}
void loader_port_delay_ms(uint32_t ms)
{
k_msleep(ms);
}
static uint64_t s_time_end;
void loader_port_start_timer(uint32_t ms)
{
s_time_end = sys_clock_timeout_end_calc(Z_TIMEOUT_MS(ms));
}
uint32_t loader_port_remaining_time(void)
{
int64_t remaining = k_ticks_to_ms_floor64(s_time_end - k_uptime_ticks());
return (remaining > 0) ? (uint32_t)remaining : 0;
}
esp_loader_error_t loader_port_change_transmission_rate(uint32_t baudrate)
{
struct uart_config uart_config;
if (!device_is_ready(uart_dev)) {
return ESP_LOADER_ERROR_FAIL;
}
if (uart_config_get(uart_dev, &uart_config) != 0) {
return ESP_LOADER_ERROR_FAIL;
}
uart_config.baudrate = baudrate;
if (uart_configure(uart_dev, &uart_config) != 0) {
return ESP_LOADER_ERROR_FAIL;
}
/* bitrate-change can require tty re-configuration */
return configure_tty();
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2022 KT-Elektronik, Klaucke und Partner GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "esp_loader_io.h"
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
const struct device *uart_dev;
const struct gpio_dt_spec enable_spec;
const struct gpio_dt_spec boot_spec;
} loader_zephyr_config_t;
esp_loader_error_t loader_port_zephyr_init(const loader_zephyr_config_t *config);
#ifdef __cplusplus
}
#endif