Merge branch 'bugfix/backport_to_2.1' into 'release/v2.1'
Backport several bug fixes to 2.1 branch See merge request !1318
This commit is contained in:
commit
a73c78a85b
20 changed files with 332 additions and 78 deletions
|
@ -142,6 +142,8 @@ esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz);
|
||||||
* can call sdmmc_host_do_transaction as long as other sdmmc_host_*
|
* can call sdmmc_host_do_transaction as long as other sdmmc_host_*
|
||||||
* functions are not called.
|
* functions are not called.
|
||||||
*
|
*
|
||||||
|
* @attention Data buffer passed in cmdinfo->data must be in DMA capable memory
|
||||||
|
*
|
||||||
* @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
|
* @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
|
||||||
* @param cmdinfo pointer to structure describing command and data to transfer
|
* @param cmdinfo pointer to structure describing command and data to transfer
|
||||||
* @return
|
* @return
|
||||||
|
@ -149,6 +151,8 @@ esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz);
|
||||||
* - ESP_ERR_TIMEOUT if response or data transfer has timed out
|
* - ESP_ERR_TIMEOUT if response or data transfer has timed out
|
||||||
* - ESP_ERR_INVALID_CRC if response or data transfer CRC check has failed
|
* - ESP_ERR_INVALID_CRC if response or data transfer CRC check has failed
|
||||||
* - ESP_ERR_INVALID_RESPONSE if the card has sent an invalid response
|
* - ESP_ERR_INVALID_RESPONSE if the card has sent an invalid response
|
||||||
|
* - ESP_ERR_INVALID_SIZE if the size of data transfer is not valid in SD protocol
|
||||||
|
* - ESP_ERR_INVALID_ARG if the data buffer is not in DMA capable memory
|
||||||
*/
|
*/
|
||||||
esp_err_t sdmmc_host_do_transaction(int slot, sdmmc_command_t* cmdinfo);
|
esp_err_t sdmmc_host_do_transaction(int slot, sdmmc_command_t* cmdinfo);
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT] = {
|
||||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //23
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //23
|
||||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //24
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //24
|
||||||
{RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_MUX_SEL_M, RTC_IO_PDAC1_FUN_SEL_S, RTC_IO_PDAC1_FUN_IE_M, RTC_IO_PDAC1_RUE_M, RTC_IO_PDAC1_RDE_M, RTC_IO_PDAC1_SLP_SEL_M, RTC_IO_PDAC1_SLP_IE_M, RTC_IO_PDAC1_HOLD_M, RTC_CNTL_PDAC1_HOLD_FORCE_M, 6}, //25
|
{RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_MUX_SEL_M, RTC_IO_PDAC1_FUN_SEL_S, RTC_IO_PDAC1_FUN_IE_M, RTC_IO_PDAC1_RUE_M, RTC_IO_PDAC1_RDE_M, RTC_IO_PDAC1_SLP_SEL_M, RTC_IO_PDAC1_SLP_IE_M, RTC_IO_PDAC1_HOLD_M, RTC_CNTL_PDAC1_HOLD_FORCE_M, 6}, //25
|
||||||
{RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_MUX_SEL_M, RTC_IO_PDAC2_FUN_SEL_S, RTC_IO_PDAC2_FUN_IE_M, RTC_IO_PDAC2_RUE_M, RTC_IO_PDAC2_RDE_M, RTC_IO_PDAC2_SLP_SEL_M, RTC_IO_PDAC2_SLP_IE_M, RTC_IO_PDAC2_HOLD_M, RTC_CNTL_PDAC1_HOLD_FORCE_M, 7}, //26
|
{RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_MUX_SEL_M, RTC_IO_PDAC2_FUN_SEL_S, RTC_IO_PDAC2_FUN_IE_M, RTC_IO_PDAC2_RUE_M, RTC_IO_PDAC2_RDE_M, RTC_IO_PDAC2_SLP_SEL_M, RTC_IO_PDAC2_SLP_IE_M, RTC_IO_PDAC2_HOLD_M, RTC_CNTL_PDAC2_HOLD_FORCE_M, 7}, //26
|
||||||
{RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_MUX_SEL_M, RTC_IO_TOUCH_PAD7_FUN_SEL_S, RTC_IO_TOUCH_PAD7_FUN_IE_M, RTC_IO_TOUCH_PAD7_RUE_M, RTC_IO_TOUCH_PAD7_RDE_M, RTC_IO_TOUCH_PAD7_SLP_SEL_M, RTC_IO_TOUCH_PAD7_SLP_IE_M, RTC_IO_TOUCH_PAD7_HOLD_M, RTC_CNTL_TOUCH_PAD7_HOLD_FORCE_M, 17}, //27
|
{RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_MUX_SEL_M, RTC_IO_TOUCH_PAD7_FUN_SEL_S, RTC_IO_TOUCH_PAD7_FUN_IE_M, RTC_IO_TOUCH_PAD7_RUE_M, RTC_IO_TOUCH_PAD7_RDE_M, RTC_IO_TOUCH_PAD7_SLP_SEL_M, RTC_IO_TOUCH_PAD7_SLP_IE_M, RTC_IO_TOUCH_PAD7_HOLD_M, RTC_CNTL_TOUCH_PAD7_HOLD_FORCE_M, 17}, //27
|
||||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //28
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //28
|
||||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //29
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //29
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "freertos/semphr.h"
|
#include "freertos/semphr.h"
|
||||||
#include "soc/sdmmc_reg.h"
|
#include "soc/sdmmc_reg.h"
|
||||||
#include "soc/sdmmc_struct.h"
|
#include "soc/sdmmc_struct.h"
|
||||||
|
#include "esp_heap_alloc_caps.h"
|
||||||
#include "driver/sdmmc_types.h"
|
#include "driver/sdmmc_types.h"
|
||||||
#include "driver/sdmmc_defs.h"
|
#include "driver/sdmmc_defs.h"
|
||||||
#include "driver/sdmmc_host.h"
|
#include "driver/sdmmc_host.h"
|
||||||
|
@ -105,9 +106,16 @@ esp_err_t sdmmc_host_do_transaction(int slot, sdmmc_command_t* cmdinfo)
|
||||||
// convert cmdinfo to hardware register value
|
// convert cmdinfo to hardware register value
|
||||||
sdmmc_hw_cmd_t hw_cmd = make_hw_cmd(cmdinfo);
|
sdmmc_hw_cmd_t hw_cmd = make_hw_cmd(cmdinfo);
|
||||||
if (cmdinfo->data) {
|
if (cmdinfo->data) {
|
||||||
// these constraints should be handled by upper layer
|
if (cmdinfo->datalen < 4 || cmdinfo->blklen % 4 != 0) {
|
||||||
assert(cmdinfo->datalen >= 4);
|
ESP_LOGD(TAG, "%s: invalid size: total=%d block=%d",
|
||||||
assert(cmdinfo->blklen % 4 == 0);
|
__func__, cmdinfo->datalen, cmdinfo->blklen);
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
if ((intptr_t) cmdinfo->data % 4 != 0 ||
|
||||||
|
!esp_ptr_dma_capable(cmdinfo->data)) {
|
||||||
|
ESP_LOGD(TAG, "%s: buffer %p can not be used for DMA", __func__, cmdinfo->data);
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
// this clears "owned by IDMAC" bits
|
// this clears "owned by IDMAC" bits
|
||||||
memset(s_dma_desc, 0, sizeof(s_dma_desc));
|
memset(s_dma_desc, 0, sizeof(s_dma_desc));
|
||||||
// initialize first descriptor
|
// initialize first descriptor
|
||||||
|
|
|
@ -259,3 +259,64 @@ TEST_CASE("SPI Master test, interaction of multiple devs", "[spi][ignore]") {
|
||||||
destroy_spi_bus(handle1);
|
destroy_spi_bus(handle1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("SPI Master no response when switch from host1 (HSPI) to host2 (VSPI)", "[spi]")
|
||||||
|
{
|
||||||
|
//spi config
|
||||||
|
spi_bus_config_t bus_config;
|
||||||
|
spi_device_interface_config_t device_config;
|
||||||
|
spi_device_handle_t spi;
|
||||||
|
spi_host_device_t host;
|
||||||
|
int dma = 1;
|
||||||
|
|
||||||
|
memset(&bus_config, 0, sizeof(spi_bus_config_t));
|
||||||
|
memset(&device_config, 0, sizeof(spi_device_interface_config_t));
|
||||||
|
|
||||||
|
bus_config.miso_io_num = -1;
|
||||||
|
bus_config.mosi_io_num = 26;
|
||||||
|
bus_config.sclk_io_num = 25;
|
||||||
|
bus_config.quadwp_io_num = -1;
|
||||||
|
bus_config.quadhd_io_num = -1;
|
||||||
|
|
||||||
|
device_config.clock_speed_hz = 50000;
|
||||||
|
device_config.mode = 0;
|
||||||
|
device_config.spics_io_num = -1;
|
||||||
|
device_config.queue_size = 1;
|
||||||
|
device_config.flags = SPI_DEVICE_TXBIT_LSBFIRST | SPI_DEVICE_RXBIT_LSBFIRST;
|
||||||
|
|
||||||
|
struct spi_transaction_t transaction = {
|
||||||
|
.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA,
|
||||||
|
.length = 16,
|
||||||
|
.tx_buffer = NULL,
|
||||||
|
.rx_buffer = NULL,
|
||||||
|
.tx_data = {0x04, 0x00}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//initialize for first host
|
||||||
|
host = 1;
|
||||||
|
|
||||||
|
assert(spi_bus_initialize(host, &bus_config, dma) == ESP_OK);
|
||||||
|
assert(spi_bus_add_device(host, &device_config, &spi) == ESP_OK);
|
||||||
|
|
||||||
|
printf("before first xmit\n");
|
||||||
|
assert(spi_device_transmit(spi, &transaction) == ESP_OK);
|
||||||
|
printf("after first xmit\n");
|
||||||
|
|
||||||
|
assert(spi_bus_remove_device(spi) == ESP_OK);
|
||||||
|
assert(spi_bus_free(host) == ESP_OK);
|
||||||
|
|
||||||
|
|
||||||
|
//for second host and failed before
|
||||||
|
host = 2;
|
||||||
|
|
||||||
|
assert(spi_bus_initialize(host, &bus_config, dma) == ESP_OK);
|
||||||
|
assert(spi_bus_add_device(host, &device_config, &spi) == ESP_OK);
|
||||||
|
|
||||||
|
printf("before second xmit\n");
|
||||||
|
// the original version (bit mis-written) stucks here.
|
||||||
|
assert(spi_device_transmit(spi, &transaction) == ESP_OK);
|
||||||
|
// test case success when see this.
|
||||||
|
printf("after second xmit\n");
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -267,7 +267,7 @@ void uart_tx_flush(uint8_t uart_no);
|
||||||
* The function defined in ROM code has a bug, so we define the correct version
|
* The function defined in ROM code has a bug, so we define the correct version
|
||||||
* here for compatibility.
|
* here for compatibility.
|
||||||
*/
|
*/
|
||||||
static inline void uart_tx_wait_idle(uint8_t uart_no) {
|
static inline void IRAM_ATTR uart_tx_wait_idle(uint8_t uart_no) {
|
||||||
while(REG_GET_FIELD(UART_STATUS_REG(uart_no), UART_ST_UTX_OUT)) {
|
while(REG_GET_FIELD(UART_STATUS_REG(uart_no), UART_ST_UTX_OUT)) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
|
#include "esp_attr.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
|
@ -19,5 +20,5 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ESP32_DEBUG_OCDAWARE
|
#ifdef CONFIG_ESP32_DEBUG_OCDAWARE
|
||||||
const int USED uxTopUsedPriority = configMAX_PRIORITIES - 1;
|
const int USED DRAM_ATTR uxTopUsedPriority = configMAX_PRIORITIES - 1;
|
||||||
#endif
|
#endif
|
|
@ -214,7 +214,7 @@ BaseType_t xPortInIsrContext();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Multi-core: get current core ID */
|
/* Multi-core: get current core ID */
|
||||||
static inline uint32_t xPortGetCoreID() {
|
static inline uint32_t IRAM_ATTR xPortGetCoreID() {
|
||||||
int id;
|
int id;
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"rsr.prid %0\n"
|
"rsr.prid %0\n"
|
||||||
|
|
|
@ -121,6 +121,7 @@ typedef unsigned portBASE_TYPE UBaseType_t;
|
||||||
#include "portbenchmark.h"
|
#include "portbenchmark.h"
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
#include "esp_attr.h"
|
||||||
|
|
||||||
#define portFIRST_TASK_HOOK CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
|
#define portFIRST_TASK_HOOK CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
|
||||||
|
|
||||||
|
|
|
@ -337,7 +337,7 @@ static void returnItemToRingbufDefault(ringbuf_t *rb, void *item) {
|
||||||
uint8_t *data=(uint8_t*)item;
|
uint8_t *data=(uint8_t*)item;
|
||||||
configASSERT(((int)rb->free_ptr&3)==0);
|
configASSERT(((int)rb->free_ptr&3)==0);
|
||||||
configASSERT(data >= rb->data);
|
configASSERT(data >= rb->data);
|
||||||
configASSERT(data < rb->data+rb->size);
|
configASSERT(data <= rb->data+rb->size);
|
||||||
//Grab the buffer entry that preceeds the buffer
|
//Grab the buffer entry that preceeds the buffer
|
||||||
buf_entry_hdr_t *hdr=(buf_entry_hdr_t*)(data-sizeof(buf_entry_hdr_t));
|
buf_entry_hdr_t *hdr=(buf_entry_hdr_t*)(data-sizeof(buf_entry_hdr_t));
|
||||||
configASSERT(hdr->len < rb->size);
|
configASSERT(hdr->len < rb->size);
|
||||||
|
|
|
@ -195,3 +195,26 @@ TEST_CASE("FreeRTOS ringbuffer test, w/ splitting items", "[freertos][ignore]")
|
||||||
testRingbuffer(1);
|
testRingbuffer(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("FreeRTOS ringbuffer test, check if zero-length items are handled correctly", "[freertos]")
|
||||||
|
{
|
||||||
|
rb = xRingbufferCreate(32, 0);
|
||||||
|
int r;
|
||||||
|
void *v;
|
||||||
|
size_t sz;
|
||||||
|
for (int x=0; x<128; x++) {
|
||||||
|
if (x!=127) {
|
||||||
|
//Send an item
|
||||||
|
r = xRingbufferSend(rb, NULL, 0, 10000 / portTICK_PERIOD_MS);
|
||||||
|
assert(r==pdTRUE);
|
||||||
|
}
|
||||||
|
if (x!=0) {
|
||||||
|
//Receive an item
|
||||||
|
v=xRingbufferReceive(rb, &sz, 10000 / portTICK_PERIOD_MS);
|
||||||
|
assert(sz==0);
|
||||||
|
vRingbufferReturnItem(rb, v); //actually not needed for NULL data...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vRingbufferDelete(rb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,6 @@
|
||||||
|
|
||||||
COMPONENT_ADD_INCLUDEDIRS := port/include nghttp2/lib/includes
|
COMPONENT_ADD_INCLUDEDIRS := port/include nghttp2/lib/includes
|
||||||
|
|
||||||
COMPONENT_SRCDIRS := nghttp2/lib
|
COMPONENT_SRCDIRS := nghttp2/lib port
|
||||||
|
|
||||||
# nghttp2_session.c uses assert(0) in place of abort() in some functions,
|
COMPONENT_SUBMODULES := nghttp2
|
||||||
# that miss a return statement if assertions are disabled.
|
|
||||||
# So it always needs assertions to be enabled
|
|
||||||
nghttp2/lib/nghttp2_session.o: CPPFLAGS := $(filter-out -DNDEBUG,$(CPPFLAGS))
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2f146e4d4cfe895d65599b87df7d847435f0e1b4
|
Subproject commit 3bcc416e13cc790e2fb45fcfe9111d38609c5032
|
|
@ -578,6 +578,17 @@ esp_err_t Page::mLoadEntryTable()
|
||||||
|
|
||||||
mHashList.insert(item, i);
|
mHashList.insert(item, i);
|
||||||
|
|
||||||
|
if (item.crc32 != item.calculateCrc32()) {
|
||||||
|
err = eraseEntryAndSpan(i);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
mState = PageState::INVALID;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(item.span > 0);
|
||||||
|
|
||||||
size_t span = item.span;
|
size_t span = item.span;
|
||||||
i += span - 1;
|
i += span - 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1096,6 +1096,44 @@ TEST_CASE("recovery after failure to write data", "[nvs]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("crc errors in item header are handled", "[nvs]")
|
||||||
|
{
|
||||||
|
SpiFlashEmulator emu(3);
|
||||||
|
Storage storage;
|
||||||
|
// prepare some data
|
||||||
|
TEST_ESP_OK(storage.init(0, 3));
|
||||||
|
TEST_ESP_OK(storage.writeItem(0, "ns1", static_cast<uint8_t>(1)));
|
||||||
|
TEST_ESP_OK(storage.writeItem(1, "value1", static_cast<uint32_t>(1)));
|
||||||
|
TEST_ESP_OK(storage.writeItem(1, "value2", static_cast<uint32_t>(2)));
|
||||||
|
|
||||||
|
// corrupt item header
|
||||||
|
uint32_t val = 0;
|
||||||
|
emu.write(32 * 3, &val, 4);
|
||||||
|
|
||||||
|
// check that storage can recover
|
||||||
|
TEST_ESP_OK(storage.init(0, 3));
|
||||||
|
TEST_ESP_OK(storage.readItem(1, "value2", val));
|
||||||
|
CHECK(val == 2);
|
||||||
|
// check that the corrupted item is no longer present
|
||||||
|
TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, storage.readItem(1, "value1", val));
|
||||||
|
|
||||||
|
// add more items to make the page full
|
||||||
|
for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
|
||||||
|
char item_name[Item::MAX_KEY_LENGTH + 1];
|
||||||
|
snprintf(item_name, sizeof(item_name), "item_%ld", i);
|
||||||
|
TEST_ESP_OK(storage.writeItem(1, item_name, static_cast<uint32_t>(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// corrupt another item on the full page
|
||||||
|
val = 0;
|
||||||
|
emu.write(32 * 4, &val, 4);
|
||||||
|
|
||||||
|
// check that storage can recover
|
||||||
|
TEST_ESP_OK(storage.init(0, 3));
|
||||||
|
// check that the corrupted item is no longer present
|
||||||
|
TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, storage.readItem(1, "value2", val));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("crc error in variable length item is handled", "[nvs]")
|
TEST_CASE("crc error in variable length item is handled", "[nvs]")
|
||||||
{
|
{
|
||||||
SpiFlashEmulator emu(3);
|
SpiFlashEmulator emu(3);
|
||||||
|
|
|
@ -46,6 +46,10 @@ static esp_err_t sdmmc_send_cmd_set_bus_width(sdmmc_card_t* card, int width);
|
||||||
static esp_err_t sdmmc_send_cmd_stop_transmission(sdmmc_card_t* card, uint32_t* status);
|
static esp_err_t sdmmc_send_cmd_stop_transmission(sdmmc_card_t* card, uint32_t* status);
|
||||||
static esp_err_t sdmmc_send_cmd_send_status(sdmmc_card_t* card, uint32_t* out_status);
|
static esp_err_t sdmmc_send_cmd_send_status(sdmmc_card_t* card, uint32_t* out_status);
|
||||||
static uint32_t get_host_ocr(float voltage);
|
static uint32_t get_host_ocr(float voltage);
|
||||||
|
static esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src,
|
||||||
|
size_t start_block, size_t block_count);
|
||||||
|
static esp_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst,
|
||||||
|
size_t start_block, size_t block_count);
|
||||||
|
|
||||||
|
|
||||||
esp_err_t sdmmc_card_init(const sdmmc_host_t* config,
|
esp_err_t sdmmc_card_init(const sdmmc_host_t* config,
|
||||||
|
@ -486,6 +490,37 @@ static esp_err_t sdmmc_send_cmd_send_status(sdmmc_card_t* card, uint32_t* out_st
|
||||||
|
|
||||||
esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src,
|
esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src,
|
||||||
size_t start_block, size_t block_count)
|
size_t start_block, size_t block_count)
|
||||||
|
{
|
||||||
|
esp_err_t err = ESP_OK;
|
||||||
|
size_t block_size = card->csd.sector_size;
|
||||||
|
if (esp_ptr_dma_capable(src) && (intptr_t)src % 4 == 0) {
|
||||||
|
err = sdmmc_write_sectors_dma(card, src, start_block, block_count);
|
||||||
|
} else {
|
||||||
|
// SDMMC peripheral needs DMA-capable buffers. Split the write into
|
||||||
|
// separate single block writes, if needed, and allocate a temporary
|
||||||
|
// DMA-capable buffer.
|
||||||
|
void* tmp_buf = pvPortMallocCaps(block_size, MALLOC_CAP_DMA);
|
||||||
|
if (tmp_buf == NULL) {
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
const uint8_t* cur_src = (const uint8_t*) src;
|
||||||
|
for (size_t i = 0; i < block_count; ++i) {
|
||||||
|
memcpy(tmp_buf, cur_src, block_size);
|
||||||
|
cur_src += block_size;
|
||||||
|
err = sdmmc_write_sectors_dma(card, tmp_buf, start_block + i, 1);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGD(TAG, "%s: error 0x%x writing block %d+%d",
|
||||||
|
__func__, err, start_block, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(tmp_buf);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src,
|
||||||
|
size_t start_block, size_t block_count)
|
||||||
{
|
{
|
||||||
if (start_block + block_count > card->csd.capacity) {
|
if (start_block + block_count > card->csd.capacity) {
|
||||||
return ESP_ERR_INVALID_SIZE;
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
@ -529,6 +564,37 @@ esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src,
|
||||||
|
|
||||||
esp_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst,
|
esp_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst,
|
||||||
size_t start_block, size_t block_count)
|
size_t start_block, size_t block_count)
|
||||||
|
{
|
||||||
|
esp_err_t err = ESP_OK;
|
||||||
|
size_t block_size = card->csd.sector_size;
|
||||||
|
if (esp_ptr_dma_capable(dst) && (intptr_t)dst % 4 == 0) {
|
||||||
|
err = sdmmc_read_sectors_dma(card, dst, start_block, block_count);
|
||||||
|
} else {
|
||||||
|
// SDMMC peripheral needs DMA-capable buffers. Split the read into
|
||||||
|
// separate single block reads, if needed, and allocate a temporary
|
||||||
|
// DMA-capable buffer.
|
||||||
|
void* tmp_buf = pvPortMallocCaps(block_size, MALLOC_CAP_DMA);
|
||||||
|
if (tmp_buf == NULL) {
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
uint8_t* cur_dst = (uint8_t*) dst;
|
||||||
|
for (size_t i = 0; i < block_count; ++i) {
|
||||||
|
err = sdmmc_read_sectors_dma(card, tmp_buf, start_block + i, 1);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGD(TAG, "%s: error 0x%x writing block %d+%d",
|
||||||
|
__func__, err, start_block, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(cur_dst, tmp_buf, block_size);
|
||||||
|
cur_dst += block_size;
|
||||||
|
}
|
||||||
|
free(tmp_buf);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst,
|
||||||
|
size_t start_block, size_t block_count)
|
||||||
{
|
{
|
||||||
if (start_block + block_count > card->csd.capacity) {
|
if (start_block + block_count > card->csd.capacity) {
|
||||||
return ESP_ERR_INVALID_SIZE;
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
|
|
@ -41,38 +41,59 @@ TEST_CASE("can probe SD", "[sd][ignore]")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Fill buffer pointed to by 'dst' with 'count' 32-bit ints generated
|
||||||
|
// from 'rand' with the starting value of 'seed'
|
||||||
|
static void fill_buffer(uint32_t seed, uint8_t* dst, size_t count) {
|
||||||
|
srand(seed);
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
uint32_t val = rand();
|
||||||
|
memcpy(dst + i * sizeof(uint32_t), &val, sizeof(val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the buffer pointed to by 'dst' contains 'count' 32-bit
|
||||||
|
// ints generated from 'rand' with the starting value of 'seed'
|
||||||
|
static void check_buffer(uint32_t seed, const uint8_t* src, size_t count) {
|
||||||
|
srand(seed);
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
uint32_t val;
|
||||||
|
memcpy(&val, src + i * sizeof(uint32_t), sizeof(val));
|
||||||
|
TEST_ASSERT_EQUAL_HEX32(rand(), val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void do_single_write_read_test(sdmmc_card_t* card,
|
static void do_single_write_read_test(sdmmc_card_t* card,
|
||||||
size_t start_block, size_t block_count)
|
size_t start_block, size_t block_count, size_t alignment)
|
||||||
{
|
{
|
||||||
size_t block_size = card->csd.sector_size;
|
size_t block_size = card->csd.sector_size;
|
||||||
size_t total_size = block_size * block_count;
|
size_t total_size = block_size * block_count;
|
||||||
printf(" %8d | %3d | %4.1f ", start_block, block_count, total_size / 1024.0f);
|
printf(" %8d | %3d | %d | %4.1f ", start_block, block_count, alignment, total_size / 1024.0f);
|
||||||
uint32_t* buffer = pvPortMallocCaps(total_size, MALLOC_CAP_DMA);
|
|
||||||
srand(start_block);
|
uint32_t* buffer = pvPortMallocCaps(total_size + 4, MALLOC_CAP_DMA);
|
||||||
for (size_t i = 0; i < total_size / sizeof(buffer[0]); ++i) {
|
size_t offset = alignment % 4;
|
||||||
buffer[i] = rand();
|
uint8_t* c_buffer = (uint8_t*) buffer + offset;
|
||||||
}
|
fill_buffer(start_block, c_buffer, total_size / sizeof(buffer[0]));
|
||||||
|
|
||||||
struct timeval t_start_wr;
|
struct timeval t_start_wr;
|
||||||
gettimeofday(&t_start_wr, NULL);
|
gettimeofday(&t_start_wr, NULL);
|
||||||
TEST_ESP_OK(sdmmc_write_sectors(card, buffer, start_block, block_count));
|
TEST_ESP_OK(sdmmc_write_sectors(card, c_buffer, start_block, block_count));
|
||||||
struct timeval t_stop_wr;
|
struct timeval t_stop_wr;
|
||||||
gettimeofday(&t_stop_wr, NULL);
|
gettimeofday(&t_stop_wr, NULL);
|
||||||
float time_wr = 1e3f * (t_stop_wr.tv_sec - t_start_wr.tv_sec) + 1e-3f * (t_stop_wr.tv_usec - t_start_wr.tv_usec);
|
float time_wr = 1e3f * (t_stop_wr.tv_sec - t_start_wr.tv_sec) + 1e-3f * (t_stop_wr.tv_usec - t_start_wr.tv_usec);
|
||||||
memset(buffer, 0xbb, total_size);
|
|
||||||
|
memset(buffer, 0xbb, total_size + 4);
|
||||||
|
|
||||||
struct timeval t_start_rd;
|
struct timeval t_start_rd;
|
||||||
gettimeofday(&t_start_rd, NULL);
|
gettimeofday(&t_start_rd, NULL);
|
||||||
TEST_ESP_OK(sdmmc_read_sectors(card, buffer, start_block, block_count));
|
TEST_ESP_OK(sdmmc_read_sectors(card, c_buffer, start_block, block_count));
|
||||||
struct timeval t_stop_rd;
|
struct timeval t_stop_rd;
|
||||||
gettimeofday(&t_stop_rd, NULL);
|
gettimeofday(&t_stop_rd, NULL);
|
||||||
float time_rd = 1e3f * (t_stop_rd.tv_sec - t_start_rd.tv_sec) + 1e-3f * (t_stop_rd.tv_usec - t_start_rd.tv_usec);
|
float time_rd = 1e3f * (t_stop_rd.tv_sec - t_start_rd.tv_sec) + 1e-3f * (t_stop_rd.tv_usec - t_start_rd.tv_usec);
|
||||||
|
|
||||||
printf(" | %6.2f | %.2f | %.2fs | %.2f\n",
|
printf(" | %6.2f | %5.2f | %6.2f | %5.2f\n",
|
||||||
time_wr, total_size / (time_wr / 1000) / (1024 * 1024),
|
time_wr, total_size / (time_wr / 1000) / (1024 * 1024),
|
||||||
time_rd, total_size / (time_rd / 1000) / (1024 * 1024));
|
time_rd, total_size / (time_rd / 1000) / (1024 * 1024));
|
||||||
srand(start_block);
|
check_buffer(start_block, c_buffer, total_size / sizeof(buffer[0]));
|
||||||
for (size_t i = 0; i < total_size / sizeof(buffer[0]); ++i) {
|
|
||||||
TEST_ASSERT_EQUAL_HEX32(rand(), buffer[i]);
|
|
||||||
}
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,23 +108,61 @@ TEST_CASE("can write and read back blocks", "[sd][ignore]")
|
||||||
TEST_ASSERT_NOT_NULL(card);
|
TEST_ASSERT_NOT_NULL(card);
|
||||||
TEST_ESP_OK(sdmmc_card_init(&config, card));
|
TEST_ESP_OK(sdmmc_card_init(&config, card));
|
||||||
sdmmc_card_print_info(stdout, card);
|
sdmmc_card_print_info(stdout, card);
|
||||||
printf(" sector | count | size(kB) | wr_time(ms) | wr_speed(MB/s) | rd_time(ms) | rd_speed(MB/s)\n");
|
printf(" sector | count | align | size(kB) | wr_time(ms) | wr_speed(MB/s) | rd_time(ms) | rd_speed(MB/s)\n");
|
||||||
do_single_write_read_test(card, 0, 1);
|
do_single_write_read_test(card, 0, 1, 4);
|
||||||
do_single_write_read_test(card, 0, 4);
|
do_single_write_read_test(card, 0, 4, 4);
|
||||||
do_single_write_read_test(card, 1, 16);
|
do_single_write_read_test(card, 1, 16, 4);
|
||||||
do_single_write_read_test(card, 16, 32);
|
do_single_write_read_test(card, 16, 32, 4);
|
||||||
do_single_write_read_test(card, 48, 64);
|
do_single_write_read_test(card, 48, 64, 4);
|
||||||
do_single_write_read_test(card, 128, 128);
|
do_single_write_read_test(card, 128, 128, 4);
|
||||||
do_single_write_read_test(card, card->csd.capacity - 64, 32);
|
do_single_write_read_test(card, card->csd.capacity - 64, 32, 4);
|
||||||
do_single_write_read_test(card, card->csd.capacity - 64, 64);
|
do_single_write_read_test(card, card->csd.capacity - 64, 64, 4);
|
||||||
do_single_write_read_test(card, card->csd.capacity - 8, 1);
|
do_single_write_read_test(card, card->csd.capacity - 8, 1, 4);
|
||||||
do_single_write_read_test(card, card->csd.capacity/2, 1);
|
do_single_write_read_test(card, card->csd.capacity/2, 1, 4);
|
||||||
do_single_write_read_test(card, card->csd.capacity/2, 4);
|
do_single_write_read_test(card, card->csd.capacity/2, 4, 4);
|
||||||
do_single_write_read_test(card, card->csd.capacity/2, 8);
|
do_single_write_read_test(card, card->csd.capacity/2, 8, 4);
|
||||||
do_single_write_read_test(card, card->csd.capacity/2, 16);
|
do_single_write_read_test(card, card->csd.capacity/2, 16, 4);
|
||||||
do_single_write_read_test(card, card->csd.capacity/2, 32);
|
do_single_write_read_test(card, card->csd.capacity/2, 32, 4);
|
||||||
do_single_write_read_test(card, card->csd.capacity/2, 64);
|
do_single_write_read_test(card, card->csd.capacity/2, 64, 4);
|
||||||
do_single_write_read_test(card, card->csd.capacity/2, 128);
|
do_single_write_read_test(card, card->csd.capacity/2, 128, 4);
|
||||||
|
do_single_write_read_test(card, card->csd.capacity/2, 1, 1);
|
||||||
|
do_single_write_read_test(card, card->csd.capacity/2, 8, 1);
|
||||||
|
do_single_write_read_test(card, card->csd.capacity/2, 128, 1);
|
||||||
free(card);
|
free(card);
|
||||||
sdmmc_host_deinit();
|
sdmmc_host_deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("reads and writes with an unaligned buffer", "[sd]")
|
||||||
|
{
|
||||||
|
sdmmc_host_t config = SDMMC_HOST_DEFAULT();
|
||||||
|
TEST_ESP_OK(sdmmc_host_init());
|
||||||
|
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
|
||||||
|
TEST_ESP_OK(sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config));
|
||||||
|
sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t));
|
||||||
|
TEST_ASSERT_NOT_NULL(card);
|
||||||
|
TEST_ESP_OK(sdmmc_card_init(&config, card));
|
||||||
|
|
||||||
|
const size_t buffer_size = 4096;
|
||||||
|
const size_t block_count = buffer_size / 512;
|
||||||
|
const size_t extra = 4;
|
||||||
|
uint8_t* buffer = pvPortMallocCaps(buffer_size + extra, MALLOC_CAP_DMA);
|
||||||
|
|
||||||
|
// Check read behavior: do aligned write, then unaligned read
|
||||||
|
const uint32_t seed = 0x89abcdef;
|
||||||
|
fill_buffer(seed, buffer, buffer_size / sizeof(uint32_t));
|
||||||
|
TEST_ESP_OK(sdmmc_write_sectors(card, buffer, 0, block_count));
|
||||||
|
memset(buffer, 0xcc, buffer_size + extra);
|
||||||
|
TEST_ESP_OK(sdmmc_read_sectors(card, buffer + 1, 0, block_count));
|
||||||
|
check_buffer(seed, buffer + 1, buffer_size / sizeof(uint32_t));
|
||||||
|
|
||||||
|
// Check write behavior: do unaligned write, then aligned read
|
||||||
|
fill_buffer(seed, buffer + 1, buffer_size / sizeof(uint32_t));
|
||||||
|
TEST_ESP_OK(sdmmc_write_sectors(card, buffer + 1, 8, block_count));
|
||||||
|
memset(buffer, 0xcc, buffer_size + extra);
|
||||||
|
TEST_ESP_OK(sdmmc_read_sectors(card, buffer, 8, block_count));
|
||||||
|
check_buffer(seed, buffer, buffer_size / sizeof(uint32_t));
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
free(card);
|
||||||
|
TEST_ESP_OK(sdmmc_host_deinit());
|
||||||
|
}
|
||||||
|
|
|
@ -958,7 +958,7 @@
|
||||||
#define DPORT_CAN_CLK_EN (BIT(19))
|
#define DPORT_CAN_CLK_EN (BIT(19))
|
||||||
#define DPORT_I2C_EXT1_CLK_EN (BIT(18))
|
#define DPORT_I2C_EXT1_CLK_EN (BIT(18))
|
||||||
#define DPORT_PWM0_CLK_EN (BIT(17))
|
#define DPORT_PWM0_CLK_EN (BIT(17))
|
||||||
#define DPORT_SPI_CLK_EN (BIT(16))
|
#define DPORT_SPI_CLK_EN_2 (BIT(16))
|
||||||
#define DPORT_TIMERGROUP1_CLK_EN (BIT(15))
|
#define DPORT_TIMERGROUP1_CLK_EN (BIT(15))
|
||||||
#define DPORT_EFUSE_CLK_EN (BIT(14))
|
#define DPORT_EFUSE_CLK_EN (BIT(14))
|
||||||
#define DPORT_TIMERGROUP_CLK_EN (BIT(13))
|
#define DPORT_TIMERGROUP_CLK_EN (BIT(13))
|
||||||
|
@ -968,7 +968,7 @@
|
||||||
#define DPORT_RMT_CLK_EN (BIT(9))
|
#define DPORT_RMT_CLK_EN (BIT(9))
|
||||||
#define DPORT_UHCI0_CLK_EN (BIT(8))
|
#define DPORT_UHCI0_CLK_EN (BIT(8))
|
||||||
#define DPORT_I2C_EXT0_CLK_EN (BIT(7))
|
#define DPORT_I2C_EXT0_CLK_EN (BIT(7))
|
||||||
#define DPORT_SPI_CLK_EN_2 (BIT(6))
|
#define DPORT_SPI_CLK_EN (BIT(6))
|
||||||
#define DPORT_UART1_CLK_EN (BIT(5))
|
#define DPORT_UART1_CLK_EN (BIT(5))
|
||||||
#define DPORT_I2S0_CLK_EN (BIT(4))
|
#define DPORT_I2S0_CLK_EN (BIT(4))
|
||||||
#define DPORT_WDG_CLK_EN (BIT(3))
|
#define DPORT_WDG_CLK_EN (BIT(3))
|
||||||
|
@ -992,7 +992,7 @@
|
||||||
#define DPORT_CAN_RST (BIT(19))
|
#define DPORT_CAN_RST (BIT(19))
|
||||||
#define DPORT_I2C_EXT1_RST (BIT(18))
|
#define DPORT_I2C_EXT1_RST (BIT(18))
|
||||||
#define DPORT_PWM0_RST (BIT(17))
|
#define DPORT_PWM0_RST (BIT(17))
|
||||||
#define DPORT_SPI_RST (BIT(16))
|
#define DPORT_SPI_RST_2 (BIT(16))
|
||||||
#define DPORT_TIMERGROUP1_RST (BIT(15))
|
#define DPORT_TIMERGROUP1_RST (BIT(15))
|
||||||
#define DPORT_EFUSE_RST (BIT(14))
|
#define DPORT_EFUSE_RST (BIT(14))
|
||||||
#define DPORT_TIMERGROUP_RST (BIT(13))
|
#define DPORT_TIMERGROUP_RST (BIT(13))
|
||||||
|
@ -1002,7 +1002,7 @@
|
||||||
#define DPORT_RMT_RST (BIT(9))
|
#define DPORT_RMT_RST (BIT(9))
|
||||||
#define DPORT_UHCI0_RST (BIT(8))
|
#define DPORT_UHCI0_RST (BIT(8))
|
||||||
#define DPORT_I2C_EXT0_RST (BIT(7))
|
#define DPORT_I2C_EXT0_RST (BIT(7))
|
||||||
#define DPORT_SPI_RST_2 (BIT(6))
|
#define DPORT_SPI_RST (BIT(6))
|
||||||
#define DPORT_UART1_RST (BIT(5))
|
#define DPORT_UART1_RST (BIT(5))
|
||||||
#define DPORT_I2S0_RST (BIT(4))
|
#define DPORT_I2S0_RST (BIT(4))
|
||||||
#define DPORT_WDG_RST (BIT(3))
|
#define DPORT_WDG_RST (BIT(3))
|
||||||
|
|
|
@ -14,4 +14,4 @@ API Guides
|
||||||
Deep Sleep Wake Stubs <deep-sleep-stub>
|
Deep Sleep Wake Stubs <deep-sleep-stub>
|
||||||
ULP Coprocessor <ulp>
|
ULP Coprocessor <ulp>
|
||||||
Unit Testing <unit-tests>
|
Unit Testing <unit-tests>
|
||||||
Driver <wifi>
|
WiFi Driver <wifi>
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
Wi-Fi Driver
|
Wi-Fi Driver
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Important Notes
|
|
||||||
----------------
|
|
||||||
|
|
||||||
- This document describes the implementation of only the **latest** IDF release. Backward compatibility with older versions of ESP-IDF is not guaranteed.
|
|
||||||
- This document describes the features which have already been implemented in the **latest** IDF release. For features that are now in developing/testing status, we also provide brief descriptions, while indicating the release versions in which these features will be eventually implemented.
|
|
||||||
- If you find anything wrong/ambiguous/hard to understand or inconsistent with the implementation, feel free to let us know about it on our IDF GitHub page.
|
|
||||||
|
|
||||||
|
|
||||||
ESP32 Wi-Fi Feature List
|
ESP32 Wi-Fi Feature List
|
||||||
-------------------------
|
-------------------------
|
||||||
|
@ -494,25 +487,13 @@ The scan type and other scan attributes are configured by esp_wifi_scan_start. T
|
||||||
| | in the table below. Here, min is short for scan |
|
| | in the table below. Here, min is short for scan |
|
||||||
| | time.active.min and max is short for scan_time.active.max. |
|
| | time.active.min and max is short for scan_time.active.max. |
|
||||||
| | |
|
| | |
|
||||||
| | +----+----+------------------------------------------------+ |
|
| | - min=0, max=0: scan dwells on each channel for 120 ms. |
|
||||||
| | | min| max| Description | |
|
| | - min>0, max=0: scan dwells on each channel for 120 ms. |
|
||||||
| | +====+====+================================================+ |
|
| | - min=0, max>0: scan dwells on each channel for ``max`` ms. |
|
||||||
| | | 0 | 0 | scan dwells on each channel for 120 ms. | |
|
| | - min>0, max>0: the minimum time the scan dwells on each |
|
||||||
| | | | | | |
|
| | channel is ``min`` ms. If no AP is found during this time |
|
||||||
| | +----+----+------------------------------------------------+ |
|
| | frame, the scan switches to the next channel. Otherwise, |
|
||||||
| | | >0 | 0 | scan dwells on each channel for 120 ms. | |
|
| | the scan dwells on the channel for ``max`` ms. |
|
||||||
| | | | | | |
|
|
||||||
| | +----+----+------------------------------------------------+ |
|
|
||||||
| | | >0 | >0 | The minimum time the scan dwells on each | |
|
|
||||||
| | | | | channel is min milliseconds. If no AP is found | |
|
|
||||||
| | | | | during this time frame, the scan switches | |
|
|
||||||
| | | | | to the next channel; otherwise, the scan dwells| |
|
|
||||||
| | | | | on the channel for max milliseconds. | |
|
|
||||||
| | | | | | |
|
|
||||||
| | +----+----+------------------------------------------------+ |
|
|
||||||
| | | 0 | >0 | The scan dwells on each channel for max | |
|
|
||||||
| | | | | milliseconds. | |
|
|
||||||
| | +----+----+------------------------------------------------+ |
|
|
||||||
| | |
|
| | |
|
||||||
| | If you want to improve the performance of the |
|
| | If you want to improve the performance of the |
|
||||||
| | the scan, you can try to modify these two parameters. |
|
| | the scan, you can try to modify these two parameters. |
|
||||||
|
|
|
@ -35,6 +35,10 @@ pacman --noconfirm -Syu # This step may require the terminal to be closed and re
|
||||||
|
|
||||||
pacman --noconfirm -S --needed gettext-devel gcc git make ncurses-devel flex bison gperf vim mingw-w64-i686-python2-pip unzip winpty
|
pacman --noconfirm -S --needed gettext-devel gcc git make ncurses-devel flex bison gperf vim mingw-w64-i686-python2-pip unzip winpty
|
||||||
|
|
||||||
|
# Workaround for errors when running "git submodule" commands
|
||||||
|
# See https://github.com/Alexpux/MSYS2-packages/issues/735
|
||||||
|
rm /mingw32/bin/envsubst.exe
|
||||||
|
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
|
|
||||||
pip install pyserial
|
pip install pyserial
|
||||||
|
|
Loading…
Reference in a new issue