Merge branch 'master' into feature/btdm_gatt_api

This commit is contained in:
Tian Hao 2017-01-05 15:25:03 +08:00
commit ee318d42ae
117 changed files with 5323 additions and 658 deletions

View File

@ -14,9 +14,10 @@ before_script:
- chmod 600 ~/.ssh/id_rsa
- echo -e "Host gitlab.espressif.cn\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
# if testing master branch, use github wifi libs.
# if testing other branches, use gitlab wifi libs (as maybe changes aren't merged to master yet)
- test "${CI_BUILD_REF_NAME}" = "master" || sed -i "s%https://github.com/espressif/esp32-wifi-lib%ssh://git@gitlab.espressif.cn:27227/idf/esp32-wifi-lib%" .gitmodules
# if testing master branch, use github wifi and bt libs.
# if testing other branches, use gitlab wifi and bt libs (as maybe changes aren't merged to master yet)
- test "${CI_BUILD_REF_NAME}" = "master" || sed -i "s%https://github.com/espressif/esp32-wifi-lib%${GITLAB_SSH_SERVER}/idf/esp32-wifi-lib%" .gitmodules
- test "${CI_BUILD_REF_NAME}" = "master" || sed -i "s%https://github.com/espressif/esp32-bt-lib%${GITLAB_SSH_SERVER}/idf/esp32-bt-lib%" .gitmodules
# fetch all submodules
- git submodule update --init --recursive
@ -149,11 +150,12 @@ test_build_system:
test_report:
stage: test_report
image: espressif/esp32-ci-env
only:
- master
- triggers
tags:
- test_report
- report
variables:
LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF"
TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test"
@ -165,12 +167,33 @@ test_report:
- $LOG_PATH
expire_in: 12 mos
script:
# calc log path
- VER_NUM=`git rev-list HEAD | wc -l | awk '{print $1}'`
- SHA_ID=`echo $CI_BUILD_REF | cut -c 1-7`
- REVISION="${VER_NUM}_${SHA_ID}"
# replace / to _ in branch name
- ESCAPED_BRANCH_NAME=`echo $CI_BUILD_REF_NAME | sed 's/\//___/g'`
# result path and artifacts path
- RESULT_PATH="$CI_PROJECT_NAME/$ESCAPED_BRANCH_NAME/$REVISION"
- ARTIFACTS_PATH="$GITLAB_HTTP_SERVER/idf/esp-idf/builds/$CI_BUILD_ID/artifacts/browse/$CI_BUILD_REF"
# clone test bench
- git clone $GITLAB_SSH_SERVER/yinling/auto_test_script.git
- cd auto_test_script
# generate report
- python CITestReport.py -l $LOG_PATH -t $TEST_CASE_FILE_PATH -p $REPORT_PATH
- python CITestReport.py -l $LOG_PATH -t $TEST_CASE_FILE_PATH -p $REPORT_PATH -r $RESULT_PATH -a $ARTIFACTS_PATH || FAIL=True
# commit to CI-test-result project
- git clone $GITLAB_SSH_SERVER/qa/CI-test-result.git
- rm -rf CI-test-result/RawData/$RESULT_PATH
- cp -R $CI_PROJECT_NAME CI-test-result/RawData
- cd CI-test-result
# config git user
- git config --global user.email "ci-test-result@espressif.com"
- git config --global user.name "ci-test-result"
# commit test result
- git add .
- git commit . -m "update test result for $CI_PROJECT_NAME/$CI_BUILD_REF_NAME/$CI_BUILD_REF, pipeline ID $CI_PIPELINE_ID" || exit 0
- git push origin master
- test "${FAIL}" = "True" && exit 1
push_master_to_github:
before_script:

View File

@ -36,6 +36,16 @@ This will flash the entire project (app, bootloader and partition table) to a ne
You don't need to run `make all` before running `make flash`, `make flash` will automatically rebuild anything which needs it.
# Viewing Serial Output
The `make monitor` target will use the already-installed [miniterm](http://pyserial.readthedocs.io/en/latest/tools.html#module-serial.tools.miniterm) (a part of pyserial) to display serial output from the ESP32 on the terminal console.
Exit miniterm by typing Ctrl-].
To flash and monitor output in one pass, you can run:
`make flash monitor`
# Compiling & Flashing Just the App
After the initial flash, you may just want to build and flash just your app, not the bootloader and partition table:
@ -47,6 +57,16 @@ After the initial flash, you may just want to build and flash just your app, not
(There's no downside to reflashing the bootloader and partition table each time, if they haven't changed.)
# Parallel Builds
esp-idf supports compiling multiple files in parallel, so all of the above commands can be run as `make -jN` where `N` is the number of parallel make processes to run (generally N should be equal to or one more than the number of CPU cores in your system.)
Multiple make functions can be combined into one. For example: to build the app & bootloader using 5 jobs in parallel, then flash everything, and then display serial output from the ESP32 run:
```
make -j5 flash monitor
```
# The Partition Table
Once you've compiled your project, the "build" directory will contain a binary file with a name like "my_app.bin". This is an ESP32 image binary that can be loaded by the bootloader.
@ -64,6 +84,12 @@ In both cases the factory app is flashed at offset 0x10000. If you `make partiti
For more details about partition tables and how to create custom variations, view the `docs/partition-tables.rst` file.
# Erasing Flash
The `make flash` target does not erase the entire flash contents. However it is sometimes useful to set the device back to a totally erased state, particularly when making partition table changes or OTA app updates. To erase the entire flash, run `make erase_flash`.
This can be combined with other targets, ie `make erase_flash flash` will erase everything and then re-flash the new app, bootloader and partition table.
# Resources
* The [docs directory of the esp-idf repository](docs) contains source of [esp-idf](http://esp-idf.readthedocs.io/) documentation.

View File

@ -69,9 +69,20 @@ config SECURE_BOOTLOADER_REFLASHABLE
endchoice
config SECURE_BOOT_SIGNING_KEY
string "Secure boot signing key"
config SECURE_BOOT_BUILD_SIGNED_BINARIES
bool "Sign binaries during build"
depends on SECURE_BOOT_ENABLED
default y
help
Once secure boot is enabled, bootloader will only boot if partition table and app image are signed.
If enabled, these binary files are signed as part of the build process. The file named in "Secure boot private signing key" will be used to sign the image.
If disabled, unsigned app/partition data will be built. They must be signed manually using espsecure.py (for example, on a remote signing server.)
config SECURE_BOOT_SIGNING_KEY
string "Secure boot private signing key"
depends on SECURE_BOOT_BUILD_SIGNED_BINARIES
default secure_boot_signing_key.pem
help
Path to the key file used to sign partition tables and app images for secure boot. Once secure boot is enabled, bootloader will only boot if partition table and app image are signed.
@ -85,6 +96,20 @@ config SECURE_BOOT_SIGNING_KEY
See docs/security/secure-boot.rst for details.
config SECURE_BOOT_VERIFICATION_KEY
string "Secure boot public signature verification key"
depends on SECURE_BOOT_ENABLED && !SECURE_BOOT_BUILD_SIGNED_BINARIES
default signature_verification_key.bin
help
Path to a public key file used to verify signed images. This key is compiled into the bootloader,
and may also be used to verify signatures on OTA images after download.
Key file is in raw binary format, and can be extracted from a
PEM formatted private key using the espsecure.py
extract_public_key command.
See docs/security/secure-boot.rst for details.
config SECURE_BOOT_INSECURE
bool "Allow potentially insecure options"
depends on SECURE_BOOT_ENABLED

View File

@ -43,18 +43,21 @@ bootloader: $(BOOTLOADER_BIN)
ESPTOOL_ALL_FLASH_ARGS += $(BOOTLOADER_OFFSET) $(BOOTLOADER_BIN)
bootloader-flash: $(BOOTLOADER_BIN)
bootloader-flash: $(BOOTLOADER_BIN) $(call prereq_if_explicit,erase_flash)
$(ESPTOOLPY_WRITE_FLASH) 0x1000 $^
else ifdef CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH
# One time flashing requires user to run esptool.py command themselves,
# and warning is printed about inability to reflash.
#
# The flashing command is deliberately printed without an auto-reset
# step, so the device doesn't immediately reset to flash itself.
bootloader: $(BOOTLOADER_BIN)
@echo $(SEPARATOR)
@echo "Bootloader built. One-time flash command is:"
@echo "$(ESPTOOLPY_WRITE_FLASH) $(BOOTLOADER_OFFSET) $(BOOTLOADER_BIN)"
@echo "$(subst hard_reset,no_reset,$(ESPTOOLPY_WRITE_FLASH)) $(BOOTLOADER_OFFSET) $(BOOTLOADER_BIN)"
@echo $(SEPARATOR)
@echo "* IMPORTANT: After first boot, BOOTLOADER CANNOT BE RE-FLASHED on same device"
@ -65,8 +68,17 @@ else ifdef CONFIG_SECURE_BOOTLOADER_REFLASHABLE
BOOTLOADER_DIGEST_BIN := $(BOOTLOADER_BUILD_DIR)/bootloader-reflash-digest.bin
SECURE_BOOTLOADER_KEY := $(BOOTLOADER_BUILD_DIR)/secure-bootloader-key.bin
ifdef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
$(SECURE_BOOTLOADER_KEY): $(SECURE_BOOT_SIGNING_KEY)
$(Q) $(ESPSECUREPY) digest_private_key -k $< $@
$(ESPSECUREPY) digest_private_key -k $< $@
else
$(SECURE_BOOTLOADER_KEY):
@echo "No pre-generated key for a reflashable secure bootloader is available, due to signing configuration."
@echo "To generate one, you can use this command:"
@echo "espsecure.py generate_flash_encryption_key $@"
@echo "then re-run make."
exit 1
endif
bootloader: $(BOOTLOADER_DIGEST_BIN)
@echo $(SEPARATOR)

View File

@ -40,6 +40,7 @@
#include "esp_image_format.h"
#include "esp_secure_boot.h"
#include "esp_flash_encrypt.h"
#include "esp_flash_partitions.h"
#include "bootloader_flash.h"
#include "bootloader_config.h"
@ -59,7 +60,7 @@ extern void Cache_Flush(int);
void bootloader_main();
static void unpack_load_app(const esp_partition_pos_t *app_node);
void print_flash_info(const esp_image_header_t* pfhdr);
void set_cache_and_start_app(uint32_t drom_addr,
static void set_cache_and_start_app(uint32_t drom_addr,
uint32_t drom_load_addr,
uint32_t drom_size,
uint32_t irom_addr,
@ -116,16 +117,14 @@ bool load_partition_table(bootloader_state_t* bs)
{
const esp_partition_info_t *partitions;
const int ESP_PARTITION_TABLE_DATA_LEN = 0xC00; /* length of actual data (signature is appended to this) */
const int MAX_PARTITIONS = ESP_PARTITION_TABLE_DATA_LEN / sizeof(esp_partition_info_t);
char *partition_usage;
ESP_LOGI(TAG, "Partition Table:");
ESP_LOGI(TAG, "## Label Usage Type ST Offset Length");
esp_err_t err;
int num_partitions;
#ifdef CONFIG_SECURE_BOOT_ENABLED
if(esp_secure_boot_enabled()) {
ESP_LOGI(TAG, "Verifying partition table signature...");
esp_err_t err = esp_secure_boot_verify_signature(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
err = esp_secure_boot_verify_signature(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to verify partition table signature.");
return false;
@ -141,17 +140,21 @@ bool load_partition_table(bootloader_state_t* bs)
}
ESP_LOGD(TAG, "mapped partition table 0x%x at 0x%x", ESP_PARTITION_TABLE_ADDR, (intptr_t)partitions);
for(int i = 0; i < MAX_PARTITIONS; i++) {
err = esp_partition_table_basic_verify(partitions, true, &num_partitions);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to verify partition table");
return false;
}
ESP_LOGI(TAG, "Partition Table:");
ESP_LOGI(TAG, "## Label Usage Type ST Offset Length");
for(int i = 0; i < num_partitions; i++) {
const esp_partition_info_t *partition = &partitions[i];
ESP_LOGD(TAG, "load partition table entry 0x%x", (intptr_t)partition);
ESP_LOGD(TAG, "type=%x subtype=%x", partition->type, partition->subtype);
partition_usage = "unknown";
if (partition->magic != ESP_PARTITION_MAGIC) {
/* invalid partition definition indicates end-of-table */
break;
}
/* valid partition table */
switch(partition->type) {
case PART_TYPE_APP: /* app partition */
@ -266,7 +269,7 @@ void bootloader_main()
if (bs.ota_info.offset != 0) { // check if partition table has OTA info partition
//ESP_LOGE("OTA info sector handling is not implemented");
if (bs.ota_info.size < 2 * sizeof(esp_ota_select_entry_t)) {
if (bs.ota_info.size < 2 * SPI_SEC_SIZE) {
ESP_LOGE(TAG, "ERROR: ota_info partition size %d is too small (minimum %d bytes)", bs.ota_info.size, sizeof(esp_ota_select_entry_t));
return;
}
@ -275,10 +278,9 @@ void bootloader_main()
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", bs.ota_info.offset, bs.ota_info.size);
return;
}
sa = ota_select_map[0];
sb = ota_select_map[1];
memcpy(&sa, ota_select_map, sizeof(esp_ota_select_entry_t));
memcpy(&sb, (uint8_t *)ota_select_map + SPI_SEC_SIZE, sizeof(esp_ota_select_entry_t));
bootloader_munmap(ota_select_map);
if(sa.ota_seq == 0xFFFFFFFF && sb.ota_seq == 0xFFFFFFFF) {
// init status flash
if (bs.factory.offset != 0) { // if have factory bin,boot factory bin
@ -365,7 +367,6 @@ void bootloader_main()
unpack_load_app(&load_part_pos);
}
static void unpack_load_app(const esp_partition_pos_t* partition)
{
esp_err_t err;
@ -413,6 +414,9 @@ static void unpack_load_app(const esp_partition_pos_t* partition)
image_header.spi_size,
(unsigned)image_header.entry_addr);
/* Important: From here on this function cannot access any global data (bss/data segments),
as loading the app image may overwrite these.
*/
for (int segment = 0; segment < image_header.segment_count; segment++) {
esp_image_segment_header_t segment_header;
uint32_t data_offs;
@ -468,6 +472,31 @@ static void unpack_load_app(const esp_partition_pos_t* partition)
segment_header.load_addr, segment_header.data_len, segment_header.data_len, (load)?"load":(map)?"map":"");
if (load) {
intptr_t sp, start_addr, end_addr;
ESP_LOGV(TAG, "bootloader_mmap data_offs=%08x data_len=%08x", data_offs, segment_header.data_len);
start_addr = segment_header.load_addr;
end_addr = start_addr + segment_header.data_len;
/* Before loading segment, check it doesn't clobber
bootloader RAM... */
if (end_addr < 0x40000000) {
sp = (intptr_t)get_sp();
if (end_addr > sp) {
ESP_LOGE(TAG, "Segment %d end address %08x overlaps bootloader stack %08x - can't load",
segment, end_addr, sp);
return;
}
if (end_addr > sp - 256) {
/* We don't know for sure this is the stack high water mark, so warn if
it seems like we may overflow.
*/
ESP_LOGW(TAG, "Segment %d end address %08x close to stack pointer %08x",
segment, end_addr, sp);
}
}
const void *data = bootloader_mmap(data_offs, segment_header.data_len);
if(!data) {
ESP_LOGE(TAG, "bootloader_mmap(0x%xc, 0x%x) failed",
@ -488,7 +517,7 @@ static void unpack_load_app(const esp_partition_pos_t* partition)
image_header.entry_addr);
}
void set_cache_and_start_app(
static void set_cache_and_start_app(
uint32_t drom_addr,
uint32_t drom_load_addr,
uint32_t drom_size,

View File

@ -17,8 +17,26 @@ ifdef CONFIG_SECURE_BOOT_ENABLED
# this path is created relative to the component build directory
SECURE_BOOT_VERIFICATION_KEY := $(abspath signature_verification_key.bin)
$(SECURE_BOOT_VERIFICATION_KEY): $(SECURE_BOOT_SIGNING_KEY)
ifdef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
# verification key derived from signing key.
$(SECURE_BOOT_VERIFICATION_KEY): $(SECURE_BOOT_SIGNING_KEY) $(SDKCONFIG_MAKEFILE)
$(ESPSECUREPY) extract_public_key --keyfile $< $@
else
# find the configured public key file
ORIG_SECURE_BOOT_VERIFICATION_KEY := $(call resolvepath,$(call dequote,$(CONFIG_SECURE_BOOT_VERIFICATION_KEY)),$(PROJECT_PATH))
$(ORIG_SECURE_BOOT_VERIFICATION_KEY):
@echo "Secure boot verification public key '$@' missing."
@echo "This can be extracted from the private signing key, see"
@echo "docs/security/secure-boot.rst for details."
exit 1
# copy it into the build dir, so the secure boot verification key has
# a predictable file name
$(SECURE_BOOT_VERIFICATION_KEY): $(ORIG_SECURE_BOOT_VERIFICATION_KEY) $(SDKCONFIG_MAKEFILE)
$(summary) CP $< $@
cp $< $@
endif
COMPONENT_EXTRA_CLEAN += $(SECURE_BOOT_VERIFICATION_KEY)

View File

@ -13,32 +13,43 @@
// limitations under the License.
#include "esp_flash_partitions.h"
#include "esp_log.h"
#include "rom/spi_flash.h"
static const char *TAG = "flash_parts";
esp_err_t esp_partition_table_basic_verify(const esp_partition_info_t *partition_table, bool log_errors, int *num_partitions)
{
int num_parts;
uint32_t chip_size = g_rom_flashchip.chip_size;
*num_partitions = 0;
for(num_parts = 0; num_parts < ESP_PARTITION_TABLE_MAX_ENTRIES; num_parts++) {
const esp_partition_info_t *part = &partition_table[num_parts];
if(part->magic == 0xFFFF
&& part->type == PART_TYPE_END
&& part->subtype == PART_SUBTYPE_END) {
if (part->magic == 0xFFFF
&& part->type == PART_TYPE_END
&& part->subtype == PART_SUBTYPE_END) {
/* TODO: check md5 */
ESP_LOGD(TAG, "partition table verified, %d entries", num_parts);
*num_partitions = num_parts;
return ESP_OK;
}
if(part->magic != ESP_PARTITION_MAGIC) {
if (part->magic != ESP_PARTITION_MAGIC) {
if (log_errors) {
ESP_LOGE(TAG, "partition %d invalid magic number 0x%x", num_parts, part->magic);
}
return ESP_ERR_INVALID_STATE;
}
const esp_partition_pos_t *pos = &part->pos;
if (pos->offset > chip_size || pos->offset + pos->size > chip_size) {
if (log_errors) {
ESP_LOGE(TAG, "partition %d invalid - offset 0x%x size 0x%x exceeds flash chip size 0x%x",
num_parts, pos->offset, pos->size, chip_size);
}
return ESP_ERR_INVALID_SIZE;
}
}
if (log_errors) {

View File

@ -80,7 +80,7 @@ static bt_status_t btc_task_post(btc_msg_t *msg)
return BT_STATUS_PARM_INVALID;
}
if (xQueueSend(xBtcQueue, msg, 10 / portTICK_RATE_MS) != pdTRUE) {
if (xQueueSend(xBtcQueue, msg, 10 / portTICK_PERIOD_MS) != pdTRUE) {
LOG_ERROR("Btc Post failed\n");
return BT_STATUS_BUSY;
}

View File

@ -177,7 +177,7 @@ void hci_hal_h4_task_post(void)
evt.sig = 0xff;
evt.par = 0;
if (xQueueSend(xHciH4Queue, &evt, 10 / portTICK_RATE_MS) != pdTRUE) {
if (xQueueSend(xHciH4Queue, &evt, 10 / portTICK_PERIOD_MS) != pdTRUE) {
LOG_ERROR("xHciH4Queue failed\n");
}
}

View File

@ -146,7 +146,7 @@ void hci_host_task_post(void)
evt.sig = 0xff;
evt.par = 0;
if (xQueueSend(xHciHostQueue, &evt, 10 / portTICK_RATE_MS) != pdTRUE) {
if (xQueueSend(xHciHostQueue, &evt, 10 / portTICK_PERIOD_MS) != pdTRUE) {
LOG_ERROR("xHciHostQueue failed\n");
}
}

View File

@ -137,9 +137,9 @@ osi_sem_wait(osi_sem_t *sem, uint32_t timeout)
StartTime = xTaskGetTickCount();
if (timeout != 0) {
if (xSemaphoreTake(*sem, timeout / portTICK_RATE_MS) == pdTRUE) {
if (xSemaphoreTake(*sem, timeout / portTICK_PERIOD_MS) == pdTRUE) {
EndTime = xTaskGetTickCount();
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
Elapsed = (EndTime - StartTime) * portTICK_PERIOD_MS;
if (Elapsed == 0) {
Elapsed = 1;
@ -153,7 +153,7 @@ osi_sem_wait(osi_sem_t *sem, uint32_t timeout)
while (xSemaphoreTake(*sem, portMAX_DELAY) != pdTRUE);
EndTime = xTaskGetTickCount();
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
Elapsed = (EndTime - StartTime) * portTICK_PERIOD_MS;
if (Elapsed == 0) {
Elapsed = 1;
@ -190,7 +190,7 @@ osi_now(void)
void osi_delay_ms(uint32_t ms)
{
vTaskDelay(ms / portTICK_RATE_MS);
vTaskDelay(ms / portTICK_PERIOD_MS);
}

View File

@ -338,7 +338,7 @@ void btu_task_post(uint32_t sig)
evt.sig = sig;
evt.par = 0;
if (xQueueSend(xBtuQueue, &evt, 10 / portTICK_RATE_MS) != pdTRUE) {
if (xQueueSend(xBtuQueue, &evt, 10 / portTICK_PERIOD_MS) != pdTRUE) {
LOG_ERROR("xBtuQueue failed\n");
}
}

View File

@ -85,7 +85,7 @@ static int32_t IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw)
static int32_t IRAM_ATTR semphr_take_wrapper(void *semphr, uint32_t block_time_ms)
{
return (int32_t)xSemaphoreTake(semphr, block_time_ms / portTICK_RATE_MS);
return (int32_t)xSemaphoreTake(semphr, block_time_ms / portTICK_PERIOD_MS);
}
static void *IRAM_ATTR mutex_create_wrapper(void)

View File

@ -72,45 +72,59 @@ const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT] = {
GPIO_PIN_REG_39
};
esp_err_t gpio_pullup_en(gpio_num_t gpio_num) {
typedef struct {
gpio_isr_t fn; /*!< isr function */
void* args; /*!< isr function args */
} gpio_isr_func_t;
static gpio_isr_func_t* gpio_isr_func = NULL;
static gpio_isr_handle_t gpio_isr_handle;
static portMUX_TYPE gpio_spinlock = portMUX_INITIALIZER_UNLOCKED;
esp_err_t gpio_pullup_en(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
if(RTC_GPIO_IS_VALID_GPIO(gpio_num)){
if (RTC_GPIO_IS_VALID_GPIO(gpio_num)) {
rtc_gpio_pullup_en(gpio_num);
}else{
} else {
REG_SET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU);
}
return ESP_OK;
}
esp_err_t gpio_pullup_dis(gpio_num_t gpio_num) {
esp_err_t gpio_pullup_dis(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
if(RTC_GPIO_IS_VALID_GPIO(gpio_num)){
if (RTC_GPIO_IS_VALID_GPIO(gpio_num)) {
rtc_gpio_pullup_dis(gpio_num);
}else{
} else {
REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU);
}
return ESP_OK;
}
esp_err_t gpio_pulldown_en(gpio_num_t gpio_num) {
esp_err_t gpio_pulldown_en(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
if(RTC_GPIO_IS_VALID_GPIO(gpio_num)){
if (RTC_GPIO_IS_VALID_GPIO(gpio_num)) {
rtc_gpio_pulldown_en(gpio_num);
}else{
REG_SET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD);
} else {
REG_SET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD);
}
return ESP_OK;
}
esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num) {
esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
if(RTC_GPIO_IS_VALID_GPIO(gpio_num)){
rtc_gpio_pulldown_dis(gpio_num);
}else{
if (RTC_GPIO_IS_VALID_GPIO(gpio_num)) {
rtc_gpio_pulldown_dis(gpio_num);
} else {
REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD);
}
return ESP_OK;
}
esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
@ -161,7 +175,7 @@ static esp_err_t gpio_output_enable(gpio_num_t gpio_num)
esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
GPIO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "GPIO output gpio_num error", ESP_ERR_INVALID_ARG);
if (level) {
if (gpio_num < 32) {
GPIO.out_w1ts = (1 << gpio_num);
@ -323,6 +337,96 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
return ESP_OK;
}
void IRAM_ATTR gpio_intr_service(void* arg)
{
//GPIO intr process
uint32_t gpio_num = 0;
//read status to get interrupt status for GPIO0-31
uint32_t gpio_intr_status;
gpio_intr_status = GPIO.status;
//read status1 to get interrupt status for GPIO32-39
uint32_t gpio_intr_status_h;
gpio_intr_status_h = GPIO.status1.intr_st;
if (gpio_isr_func == NULL) {
return;
}
do {
if (gpio_num < 32) {
if (gpio_intr_status & BIT(gpio_num)) { //gpio0-gpio31
if (gpio_isr_func[gpio_num].fn != NULL) {
gpio_isr_func[gpio_num].fn(gpio_isr_func[gpio_num].args);
}
GPIO.status_w1tc = BIT(gpio_num);
}
} else {
if (gpio_intr_status_h & BIT(gpio_num - 32)) {
if (gpio_isr_func[gpio_num].fn != NULL) {
gpio_isr_func[gpio_num].fn(gpio_isr_func[gpio_num].args);
}
GPIO.status1_w1tc.intr_st = BIT(gpio_num - 32);
}
}
} while (++gpio_num < GPIO_PIN_COUNT);
}
esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void* args)
{
GPIO_CHECK(gpio_isr_func != NULL, "GPIO isr service is not installed, call gpio_install_isr_service() first", ESP_ERR_INVALID_STATE);
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&gpio_spinlock);
gpio_intr_disable(gpio_num);
if (gpio_isr_func) {
gpio_isr_func[gpio_num].fn = isr_handler;
gpio_isr_func[gpio_num].args = args;
}
gpio_intr_enable(gpio_num);
portEXIT_CRITICAL(&gpio_spinlock);
return ESP_OK;
}
esp_err_t gpio_isr_handler_remove(gpio_num_t gpio_num)
{
GPIO_CHECK(gpio_isr_func != NULL, "GPIO isr service is not installed, call gpio_install_isr_service() first", ESP_ERR_INVALID_STATE);
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&gpio_spinlock);
gpio_intr_disable(gpio_num);
if (gpio_isr_func) {
gpio_isr_func[gpio_num].fn = NULL;
gpio_isr_func[gpio_num].args = NULL;
}
portEXIT_CRITICAL(&gpio_spinlock);
return ESP_OK;
}
esp_err_t gpio_install_isr_service(int intr_alloc_flags)
{
GPIO_CHECK(gpio_isr_func == NULL, "GPIO isr service already installed", ESP_FAIL);
esp_err_t ret;
portENTER_CRITICAL(&gpio_spinlock);
gpio_isr_func = (gpio_isr_func_t*) calloc(GPIO_NUM_MAX, sizeof(gpio_isr_func_t));
if (gpio_isr_func == NULL) {
ret = ESP_ERR_NO_MEM;
} else {
ret = gpio_isr_register(gpio_intr_service, NULL, intr_alloc_flags, &gpio_isr_handle);
}
portEXIT_CRITICAL(&gpio_spinlock);
return ret;
}
void gpio_uninstall_isr_service()
{
if (gpio_isr_func == NULL) {
return;
}
portENTER_CRITICAL(&gpio_spinlock);
esp_intr_free(gpio_isr_handle);
free(gpio_isr_func);
gpio_isr_func = NULL;
portEXIT_CRITICAL(&gpio_spinlock);
return;
}
esp_err_t gpio_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, gpio_isr_handle_t *handle)
{
GPIO_CHECK(fn, "GPIO ISR null", ESP_ERR_INVALID_ARG);
@ -334,7 +438,7 @@ esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
esp_err_t ret = ESP_OK;
if ((intr_type == GPIO_INTR_LOW_LEVEL) || (intr_type == GPIO_INTR_HIGH_LEVEL)) {
if (( intr_type == GPIO_INTR_LOW_LEVEL ) || ( intr_type == GPIO_INTR_HIGH_LEVEL )) {
GPIO.pin[gpio_num].int_type = intr_type;
GPIO.pin[gpio_num].wakeup_enable = 0x1;
} else {

1037
components/driver/i2c.c Normal file

File diff suppressed because it is too large Load Diff

807
components/driver/i2s.c Normal file
View File

@ -0,0 +1,807 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 <esp_types.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/xtensa_api.h"
#include "soc/dport_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/sens_reg.h"
#include "rom/lldesc.h"
#include "driver/gpio.h"
#include "driver/i2s.h"
#include "esp_intr.h"
#include "esp_err.h"
#include "esp_log.h"
static const char* I2S_TAG = "I2S";
#define I2S_CHECK(a, str, ret) if (!(a)) { \
ESP_LOGE(I2S_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
return (ret); \
}
#define I2S_BASE_CLK (2*APB_CLK_FREQ)
#define I2S_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_spinlock[i2s_num])
#define I2S_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_spinlock[i2s_num])
#define I2S_ENTER_CRITICAL() portENTER_CRITICAL(&i2s_spinlock[i2s_num])
#define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock[i2s_num])
#define gpio_matrix_out_check(a, b, c, d) if(a != -1) gpio_matrix_out(a, b, c, d) //if pin = -1, do not need to configure
#define gpio_matrix_in_check(a, b, c) if(a != -1) gpio_matrix_in(a, b, c)
/**
* @brief DMA buffer object
*
*/
typedef struct {
char **buf;
int buf_size;
int rw_pos;
void *curr_ptr;
SemaphoreHandle_t mux;
xQueueHandle queue;
lldesc_t **desc;
} i2s_dma_t;
/**
* @brief I2S object instance
*
*/
typedef struct {
i2s_port_t i2s_num; /*!< I2S port number*/
int queue_size; /*!< I2S event queue size*/
QueueHandle_t i2s_queue; /*!< I2S queue handler*/
int dma_buf_count; /*!< DMA buffer count, number of buffer*/
int dma_buf_len; /*!< DMA buffer length, length of each buffer*/
i2s_dma_t *rx; /*!< DMA Tx buffer*/
i2s_dma_t *tx; /*!< DMA Rx buffer*/
i2s_isr_handle_t i2s_isr_handle; /*!< I2S Interrupt handle*/
int channel_num; /*!< Number of channels*/
int bytes_per_sample; /*!< Bytes per sample*/
i2s_mode_t mode; /*!< I2S Working mode*/
} i2s_obj_t;
static i2s_obj_t *p_i2s_obj[I2S_NUM_MAX] = {0};
static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0, &I2S1};
static portMUX_TYPE i2s_spinlock[I2S_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
static esp_err_t i2s_reset_fifo(i2s_port_t i2s_num)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
I2S_ENTER_CRITICAL();
I2S[i2s_num]->conf.rx_fifo_reset = 1;
I2S[i2s_num]->conf.rx_fifo_reset = 0;
I2S[i2s_num]->conf.tx_fifo_reset = 1;
I2S[i2s_num]->conf.tx_fifo_reset = 0;
I2S_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t i2s_clear_intr_status(i2s_port_t i2s_num, uint32_t clr_mask)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
I2S[i2s_num]->int_clr.val = clr_mask;
return ESP_OK;
}
esp_err_t i2s_enable_rx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.in_suc_eof = 1;
I2S[i2s_num]->int_ena.in_dscr_err = 1;
I2S_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t i2s_disable_rx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.in_suc_eof = 0;
I2S[i2s_num]->int_ena.in_dscr_err = 0;
I2S_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t i2s_disable_tx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.out_eof = 0;
I2S[i2s_num]->int_ena.out_dscr_err = 0;
I2S_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t i2s_enable_tx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.out_eof = 1;
I2S[i2s_num]->int_ena.out_dscr_err = 1;
I2S_EXIT_CRITICAL();
return ESP_OK;
}
static esp_err_t i2s_isr_register(i2s_port_t i2s_num, uint8_t intr_alloc_flags, void (*fn)(void*), void * arg, i2s_isr_handle_t *handle)
{
return esp_intr_alloc(ETS_I2S0_INTR_SOURCE + i2s_num, intr_alloc_flags, fn, arg, handle);
}
static esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint8_t bits, bool fuzzy)
{
int factor = (256%bits)? 384 : 256; // According to hardware codec requirement(supported 256fs or 384fs)
int clkmInteger, clkmDecimals, bck = 0;
float denom = (float)1 / 64;
int channel = 2;
float clkmdiv = (float)I2S_BASE_CLK / (rate * factor);
if (clkmdiv > 256) {
ESP_LOGE(I2S_TAG, "clkmdiv is too large\r\n");
return ESP_FAIL;
}
clkmInteger = clkmdiv;
clkmDecimals = (clkmdiv - clkmInteger) / denom;
float mclk = clkmInteger + denom * clkmDecimals;
bck = factor/(bits * channel);
I2S[i2s_num]->clkm_conf.clka_en = 0;
I2S[i2s_num]->clkm_conf.clkm_div_a = 63;
I2S[i2s_num]->clkm_conf.clkm_div_b = clkmDecimals;
I2S[i2s_num]->clkm_conf.clkm_div_num = clkmInteger;
I2S[i2s_num]->sample_rate_conf.tx_bck_div_num = bck;
I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = bck;
I2S[i2s_num]->sample_rate_conf.tx_bits_mod = bits;
I2S[i2s_num]->sample_rate_conf.rx_bits_mod = bits;
float real_rate = (float)(I2S_BASE_CLK / (bck * bits * clkmInteger)/2);
ESP_LOGI(I2S_TAG, "Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d",
rate, real_rate, bits, clkmInteger, bck, (float)I2S_BASE_CLK / mclk, real_rate *16*2, 64, clkmDecimals);
return ESP_OK;
}
static void IRAM_ATTR i2s_intr_handler_default(void *arg)
{
i2s_obj_t *p_i2s = (i2s_obj_t*) arg;
uint8_t i2s_num = p_i2s->i2s_num;
i2s_dev_t* i2s_reg = I2S[i2s_num];
i2s_event_t i2s_event;
int dummy;
portBASE_TYPE high_priority_task_awoken = 0;
lldesc_t *finish_desc;
if (i2s_reg->int_st.out_dscr_err || i2s_reg->int_st.in_dscr_err) {
ESP_LOGE(I2S_TAG, "out_dscr_err: %d or in_dscr_err:%d", i2s_reg->int_st.out_dscr_err == 1, i2s_reg->int_st.in_dscr_err == 1);
if (p_i2s->i2s_queue) {
i2s_event.type = I2S_EVENT_DMA_ERROR;
if (xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) {
xQueueReceiveFromISR(p_i2s->i2s_queue, &dummy, &high_priority_task_awoken);
}
xQueueSendFromISR(p_i2s->i2s_queue, (void * )&i2s_event, &high_priority_task_awoken);
}
}
if (i2s_reg->int_st.out_eof && p_i2s->tx) {
finish_desc = (lldesc_t*) i2s_reg->out_eof_des_addr;
// All buffers are empty. This means we have an underflow on our hands.
if (xQueueIsQueueFullFromISR(p_i2s->tx->queue)) {
xQueueReceiveFromISR(p_i2s->tx->queue, &dummy, &high_priority_task_awoken);
}
xQueueSendFromISR(p_i2s->tx->queue, (void*)(&finish_desc->buf), &high_priority_task_awoken);
if (p_i2s->i2s_queue) {
i2s_event.type = I2S_EVENT_TX_DONE;
if (xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) {
xQueueReceiveFromISR(p_i2s->i2s_queue, &dummy, &high_priority_task_awoken);
}
xQueueSendFromISR(p_i2s->i2s_queue, (void * )&i2s_event, &high_priority_task_awoken);
}
}
if (i2s_reg->int_st.in_suc_eof && p_i2s->rx) {
// All buffers are full. This means we have an overflow.
finish_desc = (lldesc_t*) i2s_reg->in_eof_des_addr;
if (xQueueIsQueueFullFromISR(p_i2s->rx->queue)) {
xQueueReceiveFromISR(p_i2s->rx->queue, &dummy, &high_priority_task_awoken);
}
xQueueSendFromISR(p_i2s->rx->queue, (void*)(&finish_desc->buf), &high_priority_task_awoken);
if (p_i2s->i2s_queue) {
i2s_event.type = I2S_EVENT_RX_DONE;
if (p_i2s->i2s_queue && xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) {
xQueueReceiveFromISR(p_i2s->i2s_queue, &dummy, &high_priority_task_awoken);
}
xQueueSendFromISR(p_i2s->i2s_queue, (void * )&i2s_event, &high_priority_task_awoken);
}
}
if (high_priority_task_awoken == pdTRUE) {
portYIELD_FROM_ISR();
}
i2s_reg->int_clr.val = I2S[i2s_num]->int_st.val;
}
static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma)
{
int bux_idx;
if (p_i2s_obj[i2s_num] == NULL) {
ESP_LOGE(I2S_TAG, "Not initialized yet");
return ESP_FAIL;
}
if (dma == NULL) {
return ESP_FAIL;
}
for (bux_idx = 0; bux_idx < p_i2s_obj[i2s_num]->dma_buf_count; bux_idx++) {
if (dma->desc && dma->desc[bux_idx])
free(dma->desc[bux_idx]);
if (dma->buf && dma->buf[bux_idx])
free(dma->buf[bux_idx]);
}
if (dma->buf)
free(dma->buf);
if (dma->desc)
free(dma->desc);
vQueueDelete(dma->queue);
vSemaphoreDelete(dma->mux);
return ESP_OK;
}
static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, int dma_buf_len)
{
int bux_idx;
int sample_size = p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num;
i2s_dma_t *dma = (i2s_dma_t*) malloc(sizeof(i2s_dma_t));
if (dma == NULL) {
ESP_LOGE(I2S_TAG, "Error malloc i2s_dma_t");
return NULL;
}
memset(dma, 0, sizeof(i2s_dma_t));
dma->buf = (char **)malloc(sizeof(char*) * dma_buf_count);
if (dma->buf == NULL) {
ESP_LOGE(I2S_TAG, "Error malloc dma buffer pointer");
return NULL;
}
memset(dma->buf, 0, sizeof(char*) * dma_buf_count);
for (bux_idx = 0; bux_idx < dma_buf_count; bux_idx++) {
dma->buf[bux_idx] = (char*) malloc(dma_buf_len * sample_size);
if (dma->buf[bux_idx] == NULL) {
ESP_LOGE(I2S_TAG, "Error malloc dma buffer");
i2s_destroy_dma_queue(i2s_num, dma);
return NULL;
}
ESP_LOGD(I2S_TAG, "Addr[%d] = %d", bux_idx, (int)dma->buf[bux_idx]);
memset(dma->buf[bux_idx], 0, dma_buf_len * sample_size);
}
dma->desc = (lldesc_t**) malloc(sizeof(lldesc_t*) * dma_buf_count);
if (dma->desc == NULL) {
ESP_LOGE(I2S_TAG, "Error malloc dma description");
i2s_destroy_dma_queue(i2s_num, dma);
return NULL;
}
for (bux_idx = 0; bux_idx < dma_buf_count; bux_idx++) {
dma->desc[bux_idx] = (lldesc_t*) malloc(sizeof(lldesc_t));
if (dma->desc[bux_idx] == NULL) {
ESP_LOGE(I2S_TAG, "Error malloc dma description entry");
i2s_destroy_dma_queue(i2s_num, dma);
return NULL;
}
}
for (bux_idx = 0; bux_idx < dma_buf_count; bux_idx++) {
dma->desc[bux_idx]->owner = 1;
dma->desc[bux_idx]->eof = 1;
dma->desc[bux_idx]->sosf = 0;
dma->desc[bux_idx]->length = dma_buf_len * sample_size;
dma->desc[bux_idx]->size = dma_buf_len * sample_size;
dma->desc[bux_idx]->buf = (uint8_t *) dma->buf[bux_idx];
dma->desc[bux_idx]->offset = 0;
dma->desc[bux_idx]->empty = (uint32_t)((bux_idx < (dma_buf_count - 1)) ? (dma->desc[bux_idx + 1]) : dma->desc[0]);
}
dma->queue = xQueueCreate(dma_buf_count - 1, sizeof(char*));
dma->mux = xSemaphoreCreateMutex();
dma->rw_pos = 0;
dma->buf_size = dma_buf_len * sample_size;
dma->curr_ptr = NULL;
ESP_LOGI(I2S_TAG, "DMA Malloc info, datalen=blocksize=%d, dma_buf_count=%d", dma_buf_len * sample_size, dma_buf_count);
return dma;
}
esp_err_t i2s_start(i2s_port_t i2s_num)
{
//start DMA link
I2S_ENTER_CRITICAL();
esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle);
I2S[i2s_num]->int_clr.val = 0xFFFFFFFF;
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
ESP_LOGD(I2S_TAG, "I2S_MODE_TX");
i2s_enable_tx_intr(i2s_num);
I2S[i2s_num]->out_link.start = 1;
I2S[i2s_num]->conf.tx_start = 1;
}
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
ESP_LOGD(I2S_TAG, "I2S_MODE_RX");
i2s_enable_rx_intr(i2s_num);
I2S[i2s_num]->in_link.start = 1;
I2S[i2s_num]->conf.rx_start = 1;
}
esp_intr_enable(p_i2s_obj[i2s_num]->i2s_isr_handle);
I2S_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t i2s_stop(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle);
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
I2S[i2s_num]->out_link.stop = 1;
I2S[i2s_num]->conf.tx_start = 0;
i2s_disable_tx_intr(i2s_num);
}
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
I2S[i2s_num]->in_link.stop = 1;
I2S[i2s_num]->conf.rx_start = 0;
i2s_disable_rx_intr(i2s_num);
}
I2S_EXIT_CRITICAL();
return 0;
}
static esp_err_t configure_dac_pin(void)
{
SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_DAC_DIG_FORCE_M);
SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_DAC_CLK_INV_M);
SET_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_DAC_XPD_FORCE_M);
SET_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC_M);
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_RUE_M);
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_RDE_M);
SET_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_DAC_XPD_FORCE_M);
SET_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_XPD_DAC_M);
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_RUE_M);
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_RDE_M);
return ESP_OK;
}
esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
if (pin == NULL) {
return configure_dac_pin();
}
if (pin->bck_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->bck_io_num)) {
ESP_LOGE(I2S_TAG, "bck_io_num error");
return ESP_FAIL;
}
if (pin->ws_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->ws_io_num)) {
ESP_LOGE(I2S_TAG, "ws_io_num error");
return ESP_FAIL;
}
if (pin->data_out_num != -1 && !GPIO_IS_VALID_GPIO(pin->data_out_num)) {
ESP_LOGE(I2S_TAG, "data_out_num error");
return ESP_FAIL;
}
if (pin->data_in_num != -1 && !GPIO_IS_VALID_GPIO(pin->data_in_num)) {
ESP_LOGE(I2S_TAG, "data_in_num error");
return ESP_FAIL;
}
int bck_sig = -1, ws_sig = -1, data_out_sig = -1, data_in_sig = -1;
//TX & RX
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
bck_sig = I2S0I_BCK_OUT_IDX;
ws_sig = I2S0I_WS_OUT_IDX;
data_in_sig = I2S0I_DATA_IN15_IDX;
if (i2s_num == I2S_NUM_1) {
bck_sig = I2S1I_BCK_OUT_IDX;
ws_sig = I2S1I_WS_OUT_IDX;
data_in_sig = I2S1I_DATA_IN15_IDX;
}
}
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
bck_sig = I2S0O_BCK_OUT_IDX;
ws_sig = I2S0O_WS_OUT_IDX;
data_out_sig = I2S0O_DATA_OUT23_IDX;
if (i2s_num == I2S_NUM_1) {
bck_sig = I2S1O_BCK_OUT_IDX;
ws_sig = I2S1O_WS_OUT_IDX;
data_out_sig = I2S1O_DATA_OUT23_IDX;
}
}
gpio_matrix_out_check(pin->data_out_num, data_out_sig, 0, 0);
gpio_matrix_in_check(pin->data_in_num, data_in_sig, 0);
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) {
gpio_matrix_out_check(pin->ws_io_num, ws_sig, 0, 0);
gpio_matrix_out_check(pin->bck_io_num, bck_sig, 0, 0);
} else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) {
gpio_matrix_in_check(pin->ws_io_num, ws_sig, 0);
gpio_matrix_in_check(pin->bck_io_num, bck_sig, 0);
}
ESP_LOGE(I2S_TAG, "data: out %d, in: %d, ws: %d, bck: %d", data_out_sig, data_in_sig, ws_sig, bck_sig);
return ESP_OK;
}
esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
I2S_CHECK((p_i2s_obj[i2s_num]->bytes_per_sample > 0), "bits_per_sample not set", ESP_FAIL);
return i2s_set_clk(i2s_num, rate, p_i2s_obj[i2s_num]->bytes_per_sample*8, 0);
}
static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_config)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
I2S_CHECK((i2s_config), "param null", ESP_FAIL);
if (i2s_num == I2S_NUM_1) {
periph_module_enable(PERIPH_I2S1_MODULE);
} else {
periph_module_enable(PERIPH_I2S0_MODULE);
}
// configure I2S data port interface.
i2s_reset_fifo(i2s_num);
//reset i2s
I2S[i2s_num]->conf.tx_reset = 1;
I2S[i2s_num]->conf.tx_reset = 0;
I2S[i2s_num]->conf.rx_reset = 1;
I2S[i2s_num]->conf.rx_reset = 0;
//reset dma
I2S[i2s_num]->lc_conf.in_rst = 1;
I2S[i2s_num]->lc_conf.in_rst = 0;
I2S[i2s_num]->lc_conf.out_rst = 1;
I2S[i2s_num]->lc_conf.out_rst = 0;
//Enable and configure DMA
I2S[i2s_num]->lc_conf.check_owner = 0;
I2S[i2s_num]->lc_conf.out_loop_test = 0;
I2S[i2s_num]->lc_conf.out_auto_wrback = 0;
I2S[i2s_num]->lc_conf.out_data_burst_en = 0;
I2S[i2s_num]->lc_conf.outdscr_burst_en = 0;
I2S[i2s_num]->lc_conf.out_no_restart_clr = 0;
I2S[i2s_num]->lc_conf.indscr_burst_en = 0;
I2S[i2s_num]->lc_conf.out_eof_mode = 1;
I2S[i2s_num]->conf2.lcd_en = 0;
I2S[i2s_num]->conf2.camera_en = 0;
I2S[i2s_num]->pdm_conf.pcm2pdm_conv_en = 0;
I2S[i2s_num]->pdm_conf.pdm2pcm_conv_en = 0;
I2S[i2s_num]->fifo_conf.dscr_en = 0;
p_i2s_obj[i2s_num]->channel_num = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1;
I2S[i2s_num]->conf_chan.tx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.tx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.tx_mono = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf_chan.rx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.rx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.rx_mono = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->fifo_conf.dscr_en = 1;//connect dma to fifo
I2S[i2s_num]->conf.tx_start = 0;
I2S[i2s_num]->conf.rx_start = 0;
if (i2s_config->mode & I2S_MODE_TX) {
I2S[i2s_num]->conf.tx_msb_right = 0;
I2S[i2s_num]->conf.tx_right_first = 0;
I2S[i2s_num]->conf.tx_slave_mod = 0; // Master
I2S[i2s_num]->fifo_conf.tx_fifo_mod_force_en = 1;//?
if (i2s_config->mode & I2S_MODE_SLAVE) {
I2S[i2s_num]->conf.tx_slave_mod = 1;//TX Slave
}
}
if (i2s_config->mode & I2S_MODE_RX) {
I2S[i2s_num]->conf.rx_msb_right = 0;
I2S[i2s_num]->conf.rx_right_first = 0;
I2S[i2s_num]->conf.rx_slave_mod = 0; // Master
I2S[i2s_num]->fifo_conf.rx_fifo_mod_force_en = 1;//?
I2S[i2s_num]->rx_eof_num = (i2s_config->dma_buf_len);
if (i2s_config->mode & I2S_MODE_SLAVE) {
I2S[i2s_num]->conf.rx_slave_mod = 1;//RX Slave
}
}
if (i2s_config->mode & I2S_MODE_DAC_BUILT_IN) {
I2S[i2s_num]->conf2.lcd_en = 1;
I2S[i2s_num]->conf.tx_right_first = 1;
I2S[i2s_num]->fifo_conf.tx_fifo_mod = 3;
}
if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S) {
I2S[i2s_num]->conf.tx_short_sync = 0;
I2S[i2s_num]->conf.rx_short_sync = 0;
I2S[i2s_num]->conf.tx_msb_shift = 1;
I2S[i2s_num]->conf.rx_msb_shift = 1;
if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S_LSB) {
if (i2s_config->mode & I2S_MODE_TX) {
I2S[i2s_num]->conf.tx_msb_shift = 0;
}
if (i2s_config->mode & I2S_MODE_RX) {
I2S[i2s_num]->conf.rx_msb_shift = 0;
}
}
}
if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM) {
I2S[i2s_num]->conf.tx_msb_shift = 0;
I2S[i2s_num]->conf.rx_msb_shift = 0;
I2S[i2s_num]->conf.tx_short_sync = 0;
I2S[i2s_num]->conf.rx_short_sync = 0;
if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM_SHORT) {
if (i2s_config->mode & I2S_MODE_TX) {
I2S[i2s_num]->conf.tx_short_sync = 1;
}
if (i2s_config->mode & I2S_MODE_RX) {
I2S[i2s_num]->conf.rx_short_sync = 1;
}
}
}
if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) && (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX)) {
I2S[i2s_num]->conf.sig_loopback = 1;
}
i2s_set_clk(i2s_num, i2s_config->sample_rate, p_i2s_obj[i2s_num]->bytes_per_sample*8, 0);
return ESP_OK;
}
esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num)
{
int total_buffer_in_bytes = p_i2s_obj[i2s_num]->dma_buf_count * p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num;
const uint32_t zero_sample[2] = { 0 };
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
while (total_buffer_in_bytes > 0) {
i2s_push_sample(i2s_num, (const char*) zero_sample, 10);
total_buffer_in_bytes -= p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num;
}
return ESP_OK;
}
esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void* i2s_queue)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
I2S_CHECK((i2s_config != NULL), "I2S configuration must not NULL", ESP_FAIL);
I2S_CHECK((i2s_config->dma_buf_count >= 2 && i2s_config->dma_buf_count <= 128), "I2S buffer count less than 128 and more than 2", ESP_FAIL);
I2S_CHECK((i2s_config->dma_buf_len >= 8 && i2s_config->dma_buf_len <= 2048), "I2S buffer length at most 2048 and more than 8", ESP_FAIL);
if (p_i2s_obj[i2s_num] == NULL) {
p_i2s_obj[i2s_num] = (i2s_obj_t*) malloc(sizeof(i2s_obj_t));
if (p_i2s_obj[i2s_num] == NULL) {
ESP_LOGE(I2S_TAG, "Malloc I2S driver error");
return ESP_FAIL;
}
p_i2s_obj[i2s_num]->i2s_num = i2s_num;
p_i2s_obj[i2s_num]->dma_buf_count = i2s_config->dma_buf_count;
p_i2s_obj[i2s_num]->dma_buf_len = i2s_config->dma_buf_len;
p_i2s_obj[i2s_num]->i2s_queue = i2s_queue;
p_i2s_obj[i2s_num]->mode = i2s_config->mode;
p_i2s_obj[i2s_num]->bytes_per_sample = i2s_config->bits_per_sample/8;
//initial dma
if (ESP_FAIL == i2s_isr_register(i2s_num, i2s_config->intr_alloc_flags, i2s_intr_handler_default, p_i2s_obj[i2s_num], &p_i2s_obj[i2s_num]->i2s_isr_handle)) {
free(p_i2s_obj[i2s_num]);
ESP_LOGE(I2S_TAG, "Register I2S Interrupt error");
return ESP_FAIL;
}
i2s_stop(i2s_num);
i2s_param_config(i2s_num, i2s_config);
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
p_i2s_obj[i2s_num]->tx = i2s_create_dma_queue(i2s_num, i2s_config->dma_buf_count, i2s_config->dma_buf_len);
if (p_i2s_obj[i2s_num]->tx == NULL) {
ESP_LOGE(I2S_TAG, "Failed to create tx dma buffer");
i2s_driver_uninstall(i2s_num);
return ESP_FAIL;
}
I2S[i2s_num]->out_link.addr = (uint32_t) p_i2s_obj[i2s_num]->tx->desc[0];
}
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
p_i2s_obj[i2s_num]->rx = i2s_create_dma_queue(i2s_num, i2s_config->dma_buf_count, i2s_config->dma_buf_len);
if (p_i2s_obj[i2s_num]->rx == NULL){
ESP_LOGE(I2S_TAG, "Failed to create rx dma buffer");
i2s_driver_uninstall(i2s_num);
return ESP_FAIL;
}
I2S[i2s_num]->in_link.addr = (uint32_t) p_i2s_obj[i2s_num]->rx->desc[0];
}
if (i2s_queue) {
p_i2s_obj[i2s_num]->i2s_queue = xQueueCreate(queue_size, sizeof(i2s_event_t));
*((QueueHandle_t*) i2s_queue) = p_i2s_obj[i2s_num]->i2s_queue;
ESP_LOGI(I2S_TAG, "queue free spaces: %d", uxQueueSpacesAvailable(p_i2s_obj[i2s_num]->i2s_queue));
} else {
p_i2s_obj[i2s_num]->i2s_queue = NULL;
}
i2s_start(i2s_num);
} else {
ESP_LOGE(I2S_TAG, "I2S driver already installed");
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
if (p_i2s_obj[i2s_num] == NULL) {
ESP_LOGI(I2S_TAG, "ALREADY NULL");
return ESP_OK;
}
i2s_stop(i2s_num);
esp_intr_free(p_i2s_obj[i2s_num]->i2s_isr_handle);
if (p_i2s_obj[i2s_num]->tx != NULL && p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
i2s_destroy_dma_queue(i2s_num, p_i2s_obj[i2s_num]->tx);
p_i2s_obj[i2s_num]->tx = NULL;
}
if (p_i2s_obj[i2s_num]->rx != NULL && p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
i2s_destroy_dma_queue(i2s_num, p_i2s_obj[i2s_num]->rx);
p_i2s_obj[i2s_num]->rx = NULL;
}
if (p_i2s_obj[i2s_num]->i2s_queue) {
vQueueDelete(p_i2s_obj[i2s_num]->i2s_queue);
p_i2s_obj[i2s_num]->i2s_queue = NULL;
}
free(p_i2s_obj[i2s_num]);
p_i2s_obj[i2s_num] = NULL;
if (i2s_num == I2S_NUM_0) {
periph_module_disable(PERIPH_I2S0_MODULE);
} else if (i2s_num == I2S_NUM_1) {
periph_module_disable(PERIPH_I2S1_MODULE);
}
return ESP_OK;
}
int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t ticks_to_wait)
{
char *data_ptr;
int bytes_can_write, bytes_writen = 0;
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
if (p_i2s_obj[i2s_num]->tx == NULL) {
return 0;
}
xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY);
while (size > 0) {
if (p_i2s_obj[i2s_num]->tx->rw_pos == p_i2s_obj[i2s_num]->tx->buf_size || p_i2s_obj[i2s_num]->tx->curr_ptr == NULL) {
if (xQueueReceive(p_i2s_obj[i2s_num]->tx->queue, &p_i2s_obj[i2s_num]->tx->curr_ptr, ticks_to_wait) == pdFALSE) {
break;
}
p_i2s_obj[i2s_num]->tx->rw_pos = 0;
}
ESP_LOGD(I2S_TAG, "size: %d, rw_pos: %d, buf_size: %d, curr_ptr: %d", size, p_i2s_obj[i2s_num]->tx->rw_pos, p_i2s_obj[i2s_num]->tx->buf_size, (int)p_i2s_obj[i2s_num]->tx->curr_ptr);
data_ptr = (char*)p_i2s_obj[i2s_num]->tx->curr_ptr;
data_ptr += p_i2s_obj[i2s_num]->tx->rw_pos;
bytes_can_write = p_i2s_obj[i2s_num]->tx->buf_size - p_i2s_obj[i2s_num]->tx->rw_pos;
if (bytes_can_write > size) {
bytes_can_write = size;
}
memcpy(data_ptr, src, bytes_can_write);
size -= bytes_can_write;
src += bytes_can_write;
p_i2s_obj[i2s_num]->tx->rw_pos += bytes_can_write;
bytes_writen += bytes_can_write;
}
xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux);
return bytes_writen;
}
int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks_to_wait)
{
char *data_ptr;
int bytes_can_read, byte_read = 0;
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
if (p_i2s_obj[i2s_num]->rx == NULL) {
return 0;
}
xSemaphoreTake(p_i2s_obj[i2s_num]->rx->mux, (portTickType)portMAX_DELAY);
while (size > 0) {
if (p_i2s_obj[i2s_num]->rx->rw_pos == p_i2s_obj[i2s_num]->rx->buf_size || p_i2s_obj[i2s_num]->rx->curr_ptr == NULL) {
if (xQueueReceive(p_i2s_obj[i2s_num]->rx->queue, &p_i2s_obj[i2s_num]->rx->curr_ptr, ticks_to_wait) == pdFALSE) {
break;
}
p_i2s_obj[i2s_num]->rx->rw_pos = 0;
}
data_ptr = (char*)p_i2s_obj[i2s_num]->rx->curr_ptr;
data_ptr += p_i2s_obj[i2s_num]->rx->rw_pos;
bytes_can_read = p_i2s_obj[i2s_num]->rx->buf_size - p_i2s_obj[i2s_num]->rx->rw_pos;
if (bytes_can_read > size) {
bytes_can_read = size;
}
memcpy(dest, data_ptr, bytes_can_read);
size -= bytes_can_read;
dest += bytes_can_read;
p_i2s_obj[i2s_num]->rx->rw_pos += bytes_can_read;
byte_read += bytes_can_read;
}
xSemaphoreGive(p_i2s_obj[i2s_num]->rx->mux);
return byte_read;
}
int i2s_push_sample(i2s_port_t i2s_num, const char *sample, TickType_t ticks_to_wait)
{
int i, bytes_to_push = 0;
char *data_ptr;
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
if (p_i2s_obj[i2s_num]->tx->rw_pos == p_i2s_obj[i2s_num]->tx->buf_size || p_i2s_obj[i2s_num]->tx->curr_ptr == NULL) {
if (xQueueReceive(p_i2s_obj[i2s_num]->tx->queue, &p_i2s_obj[i2s_num]->tx->curr_ptr, ticks_to_wait) == pdFALSE) {
return 0;
}
ESP_LOGD(I2S_TAG, "rw_pos: %d, buf_size: %d, curr_ptr: %d", p_i2s_obj[i2s_num]->tx->rw_pos, p_i2s_obj[i2s_num]->tx->buf_size, (int)p_i2s_obj[i2s_num]->tx->curr_ptr);
p_i2s_obj[i2s_num]->tx->rw_pos = 0;
}
data_ptr = (char*)p_i2s_obj[i2s_num]->tx->curr_ptr;
data_ptr += p_i2s_obj[i2s_num]->tx->rw_pos;
for (i = 0; i < p_i2s_obj[i2s_num]->bytes_per_sample; i++) {
*data_ptr++ = *sample++;
bytes_to_push ++;
}
if (p_i2s_obj[i2s_num]->channel_num == 2) {
for (i = 0; i < p_i2s_obj[i2s_num]->bytes_per_sample; i++) {
*data_ptr++ = *sample++;
bytes_to_push ++;
}
}
p_i2s_obj[i2s_num]->tx->rw_pos += p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num;
return bytes_to_push;
}
int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait)
{
int i, bytes_to_pop = 0;
char *data_ptr;
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
if (p_i2s_obj[i2s_num]->rx->rw_pos == p_i2s_obj[i2s_num]->rx->buf_size || p_i2s_obj[i2s_num]->rx->curr_ptr == NULL) {
if (xQueueReceive(p_i2s_obj[i2s_num]->rx->queue, &p_i2s_obj[i2s_num]->rx->curr_ptr, ticks_to_wait) == pdFALSE) {
return 0;
}
p_i2s_obj[i2s_num]->rx->rw_pos = 0;
}
data_ptr = (char*)p_i2s_obj[i2s_num]->rx->curr_ptr;
data_ptr += p_i2s_obj[i2s_num]->rx->rw_pos;
for (i = 0; i < p_i2s_obj[i2s_num]->bytes_per_sample; i++) {
*sample++ = *data_ptr++;
bytes_to_pop++;
}
if (p_i2s_obj[i2s_num]->channel_num == 2) {
for (i = 0; i < p_i2s_obj[i2s_num]->bytes_per_sample; i++) {
*sample++ = *data_ptr++;
bytes_to_pop++;
}
}
p_i2s_obj[i2s_num]->rx->rw_pos += p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num;
return bytes_to_pop;
}

View File

@ -156,6 +156,7 @@ typedef enum {
GPIO_NUM_37 = 37, /*!< GPIO37, input mode only */
GPIO_NUM_38 = 38, /*!< GPIO38, input mode only */
GPIO_NUM_39 = 39, /*!< GPIO39, input mode only */
GPIO_NUM_MAX = 40,
} gpio_num_t;
typedef enum {
@ -205,9 +206,8 @@ typedef enum {
} gpio_pull_mode_t;
typedef void (*gpio_isr_t)(void*);
typedef intr_handle_t gpio_isr_handle_t;
typedef void (*gpio_event_callback)(gpio_num_t gpio_intr_num);
/**
* @brief GPIO common configuration
@ -269,7 +269,7 @@ esp_err_t gpio_intr_disable(gpio_num_t gpio_num);
*
* @return
* - ESP_OK Success
* - GPIO_IS_VALID_GPIO GPIO number error
* - ESP_ERR_INVALID_ARG GPIO number error
*
*/
esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level);
@ -343,9 +343,6 @@ esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num);
/**
* @brief register GPIO interrupt handler, the handler is an ISR.
* The handler will be attached to the same CPU core that this function is running on.
* @note
* Users should know that which CPU is running and then pick a INUM that is not used by system.
* We can find the information of INUM and interrupt level in soc.h.
*
* @param fn Interrupt handler function.
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
@ -360,8 +357,6 @@ esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num);
*/
esp_err_t gpio_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, gpio_isr_handle_t *handle);
/**
* @brief Enable pull-up on GPIO.
*
@ -406,97 +401,55 @@ esp_err_t gpio_pulldown_en(gpio_num_t gpio_num);
*/
esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num);
/**
* @brief Install a GPIO ISR service, so we can assign different ISR handler for different pins
*
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Operation fail
* - ESP_ERR_NO_MEM No memory to install this service
*/
esp_err_t gpio_install_isr_service(int intr_alloc_flags);
/**
* *************** ATTENTION ********************/
/**
*@attention
* Each GPIO has its own separate configuration register, so we do not use
* a lock to serialize access to them. This works under the assumption that
* no situation will occur where two tasks try to configure the same GPIO
* pin simultaneously. It is up to the application developer to guarantee this.
*/
* @brief Un-install GPIO ISR service, free the resources.
*/
void gpio_uninstall_isr_service();
/**
*----------EXAMPLE TO CONFIGURE GPIO AS OUTPUT ------------ *
* @code{c}
* gpio_config_t io_conf;
* io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt
* io_conf.mode = GPIO_MODE_OUTPUT; //set as output mode
* io_conf.pin_bit_mask = GPIO_SEL_18 | GPIO_SEL_19; //bit mask of the pins that you want to set,e.g.GPIO18/19
* io_conf.pull_down_en = 0; //disable pull-down mode
* io_conf.pull_up_en = 0; //disable pull-up mode
* gpio_config(&io_conf); //configure GPIO with the given settings
* @endcode
**/
* @brief Add ISR handler for the corresponding GPIO.
*
* Interrupt handlers no longer need to be declared with IRAM_ATTR, unless you pass the ESP_INTR_FLAG_IRAM flag
* when allocating the ISR in gpio_install_isr_service().
* This ISR handler will be called from an ISR. So there probably is some stack size limit, and this limit
* is smaller compared to a "raw" interrupt handler due to another level of indirection.
*
* @param gpio_num GPIO number
* @param isr_handler ISR handler function for the corresponding GPIO number.
* @param args parameter for ISR handler.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE Wrong state, the ISR service has not been initialized.
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void* args);
/**
*----------EXAMPLE TO CONFIGURE GPIO AS OUTPUT ------------ *
* @code{c}
* io_conf.intr_type = GPIO_INTR_POSEDGE; //set posedge interrupt
* io_conf.mode = GPIO_MODE_INPUT; //set as input
* io_conf.pin_bit_mask = GPIO_SEL_4 | GPIO_SEL_5; //bit mask of the pins that you want to set, e.g.,GPIO4/5
* io_conf.pull_down_en = 0; //disable pull-down mode
* io_conf.pull_up_en = 1; //enable pull-up mode
* gpio_config(&io_conf); //configure GPIO with the given settings
* @endcode
*/
/**
*----------EXAMPLE TO SET ISR HANDLER ----------------------
* @code{c}
* gpio_isr_register(gpio_intr_test,NULL, 0); //hook the isr handler for GPIO interrupt
* @endcode
* @note
* 1. user should arrange the INUMs that used, better not to use a same INUM for different interrupt.
* 2. do not pick the INUM that already occupied by the system.
* 3. refer to soc.h to check which INUMs that can be used.
*/
/**
*-------------EXAMPLE OF HANDLER FUNCTION-------------------*
* @code{c}
* #include "esp_attr.h"
* void IRAM_ATTR gpio_intr_test(void* arg)
* {
* //GPIO intr process
* ets_printf("in gpio_intr\n");
* uint32_t gpio_num = 0;
* uint32_t gpio_intr_status = READ_PERI_REG(GPIO_STATUS_REG); //read status to get interrupt status for GPIO0-31
* uint32_t gpio_intr_status_h = READ_PERI_REG(GPIO_STATUS1_REG);//read status1 to get interrupt status for GPIO32-39
* SET_PERI_REG_MASK(GPIO_STATUS_W1TC_REG, gpio_intr_status); //Clear intr for gpio0-gpio31
* SET_PERI_REG_MASK(GPIO_STATUS1_W1TC_REG, gpio_intr_status_h); //Clear intr for gpio32-39
* do {
* if(gpio_num < 32) {
* if(gpio_intr_status & BIT(gpio_num)) { //gpio0-gpio31
* ets_printf("Intr GPIO%d ,val: %d\n",gpio_num,gpio_get_level(gpio_num));
* //This is an isr handler, you should post an event to process it in RTOS queue.
* }
* } else {
* if(gpio_intr_status_h & BIT(gpio_num - 32)) {
* ets_printf("Intr GPIO%d, val : %d\n",gpio_num,gpio_get_level(gpio_num));
* //This is an isr handler, you should post an event to process it in RTOS queue.
* }
* }
* } while(++gpio_num < GPIO_PIN_COUNT);
* }
* @endcode
*/
* @brief Remove ISR handler for the corresponding GPIO.
*
* @param gpio_num GPIO number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE Wrong state, the ISR service has not been initialized.
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_isr_handler_remove(gpio_num_t gpio_num);
/**
*----EXAMPLE OF I2C CONFIG AND PICK SIGNAL FOR IO MATRIX---*
* @code{c}
* gpio_config_t io_conf;
* io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt
* io_conf.mode = GPIO_MODE_INPUT_OUTPUT_OD; //set as output mode
* io_conf.pin_bit_mask = GPIO_SEL_21 | GPIO_SEL_22; //bit mask of the pins that you want to set,e.g.GPIO21/22
* io_conf.pull_down_en = 0; //disable pull-down mode
* io_conf.pull_up_en = 1; //enable pull-up mode
* gpio_config(&io_conf); //configure GPIO with the given settings
* gpio_matrix_out(21, EXT_I2C_SCL_O_IDX, 0, 0); //set output signal for io_matrix
* gpio_matrix_out(22, EXT_I2C_SDA_O_IDX, 0, 0); //set output signal for io_matrix
* gpio_matrix_in( 22, EXT_I2C_SDA_I_IDX, 0); //set input signal for io_matrix
* @endcode
*
*/
#ifdef __cplusplus
}

View File

@ -0,0 +1,514 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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.
#ifndef _DRIVER_I2C_H_
#define _DRIVER_I2C_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <esp_types.h>
#include "esp_err.h"
#include "esp_intr_alloc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/xtensa_api.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/ringbuf.h"
#include "driver/gpio.h"
#define I2C_APB_CLK_FREQ APB_CLK_FREQ /*!< I2C source clock is APB clock, 80MHz */
#define I2C_FIFO_LEN (32) /*!< I2C hardware fifo length */
typedef enum{
I2C_MODE_SLAVE = 0, /*!< I2C slave mode */
I2C_MODE_MASTER, /*!< I2C master mode */
I2C_MODE_MAX,
}i2c_mode_t;
typedef enum {
I2C_MASTER_WRITE = 0, /*!< I2C write data */
I2C_MASTER_READ, /*!< I2C read data */
} i2c_rw_t;
typedef enum {
I2C_DATA_MODE_MSB_FIRST = 0, /*!< I2C data msb first */
I2C_DATA_MODE_LSB_FIRST = 1, /*!< I2C data lsb first */
I2C_DATA_MODE_MAX
} i2c_trans_mode_t;
typedef enum{
I2C_CMD_RESTART = 0, /*!<I2C restart command */
I2C_CMD_WRITE, /*!<I2C write command */
I2C_CMD_READ, /*!<I2C read command */
I2C_CMD_STOP, /*!<I2C stop command */
I2C_CMD_END /*!<I2C end command */
}i2c_opmode_t;
typedef enum{
I2C_NUM_0 = 0, /*!< I2C port 0 */
I2C_NUM_1 , /*!< I2C port 1 */
I2C_NUM_MAX
} i2c_port_t;
typedef enum {
I2C_ADDR_BIT_7 = 0, /*!< I2C 7bit address for slave mode */
I2C_ADDR_BIT_10, /*!< I2C 10bit address for slave mode */
I2C_ADDR_BIT_MAX,
} i2c_addr_mode_t;
/**
* @brief I2C initialization parameters
*/
typedef struct{
i2c_mode_t mode; /*!< I2C mode */
gpio_num_t sda_io_num; /*!< GPIO number for I2C sda signal */
gpio_pullup_t sda_pullup_en; /*!< Internal GPIO pull mode for I2C sda signal*/
gpio_num_t scl_io_num; /*!< GPIO number for I2C scl signal */
gpio_pullup_t scl_pullup_en; /*!< Internal GPIO pull mode for I2C scl signal*/
union {
struct {
uint32_t clk_speed; /*!< I2C clock frequency for master mode, (no higher than 1MHz for now) */
} master;
struct {
uint8_t addr_10bit_en; /*!< I2C 10bit address mode enable for slave mode */
uint16_t slave_addr; /*!< I2C address for slave mode */
} slave;
};
}i2c_config_t;
typedef void* i2c_cmd_handle_t; /*!< I2C command handle */
/**
* @brief I2C driver install
*
* @param i2c_num I2C port number
* @param mode I2C mode( master or slave )
* @param slv_rx_buf_len receiving buffer size for slave mode
* @note
* Only slave mode will use this value, driver will ignore this value in master mode.
* @param slv_tx_buf_len sending buffer size for slave mode
* @note
* Only slave mode will use this value, driver will ignore this value in master mode.
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL Driver install error
*/
esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_buf_len, size_t slv_tx_buf_len, int intr_alloc_flags);
/**
* @brief I2C driver delete
*
* @param i2c_num I2C port number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_driver_delete(i2c_port_t i2c_num);
/**
* @brief I2C parameter initialization
*
* @param i2c_num I2C port number
* @param i2c_conf pointer to I2C parameter settings
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_param_config(i2c_port_t i2c_num, i2c_config_t* i2c_conf);
/**
* @brief reset I2C tx hardware fifo
*
* @param i2c_num I2C port number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_reset_tx_fifo(i2c_port_t i2c_num);
/**
* @brief reset I2C rx fifo
*
* @param i2c_num I2C port number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_reset_rx_fifo(i2c_port_t i2c_num);
/**
* @brief I2C isr handler register
*
* @param i2c_num I2C port number
* @param fn isr handler function
* @param arg parameter for isr handler function
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
* @param handle handle return from esp_intr_alloc.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_isr_register(i2c_port_t i2c_num, void (*fn)(void*), void * arg, int intr_alloc_flags, intr_handle_t *handle);
/**
* @brief to delete and free I2C isr.
*
* @param handle handle of isr.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_isr_free(intr_handle_t handle);
/**
* @brief Configure GPIO signal for I2C sck and sda
*
* @param i2c_num I2C port number
* @param sda_io_num GPIO number for I2C sda signal
* @param scl_io_num GPIO number for I2C scl signal
* @param sda_pullup_en Whether to enable the internal pullup for sda pin
* @param scl_pullup_en Whether to enable the internal pullup for scl pin
* @param mode I2C mode
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_set_pin(i2c_port_t i2c_num, gpio_num_t sda_io_num, gpio_num_t scl_io_num,
gpio_pullup_t sda_pullup_en, gpio_pullup_t scl_pullup_en, i2c_mode_t mode);
/**
* @brief Create and init I2C command link
* @note
* Before we build I2C command link, we need to call i2c_cmd_link_create() to create
* a command link.
* After we finish sending the commands, we need to call i2c_cmd_link_delete() to
* release and return the resources.
*
* @return i2c command link handler
*/
i2c_cmd_handle_t i2c_cmd_link_create();
/**
* @brief Free I2C command link
* @note
* Before we build I2C command link, we need to call i2c_cmd_link_create() to create
* a command link.
* After we finish sending the commands, we need to call i2c_cmd_link_delete() to
* release and return the resources.
*
* @param cmd_handle I2C command handle
*/
void i2c_cmd_link_delete(i2c_cmd_handle_t cmd_handle);
/**
* @brief Queue command for I2C master to generate a start signal
* @note
* Only call this function in I2C master mode
* Call i2c_master_cmd_begin() to send all queued commands
*
* @param cmd_handle I2C cmd link
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_master_start(i2c_cmd_handle_t cmd_handle);
/**
* @brief Queue command for I2C master to write one byte to I2C bus
* @note
* Only call this function in I2C master mode
* Call i2c_master_cmd_begin() to send all queued commands
*
* @param cmd_handle I2C cmd link
* @param data I2C one byte command to write to bus
* @param ack_en enable ack check for master
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_master_write_byte(i2c_cmd_handle_t cmd_handle, uint8_t data, bool ack_en);
/**
* @brief Queue command for I2C master to write buffer to I2C bus
* @note
* Only call this function in I2C master mode
* Call i2c_master_cmd_begin() to send all queued commands
*
* @param cmd_handle I2C cmd link
* @param data data to send
* @param data_len data length
* @param ack_en enable ack check for master
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_master_write(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t data_len, bool ack_en);
/**
* @brief Queue command for I2C master to read one byte from I2C bus
* @note
* Only call this function in I2C master mode
* Call i2c_master_cmd_begin() to send all queued commands
*
* @param cmd_handle I2C cmd link
* @param data pointer accept the data byte
* @param ack ack value for read command
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_master_read_byte(i2c_cmd_handle_t cmd_handle, uint8_t* data, int ack);
/**
* @brief Queue command for I2C master to read data from I2C bus
* @note
* Only call this function in I2C master mode
* Call i2c_master_cmd_begin() to send all queued commands
*
* @param cmd_handle I2C cmd link
* @param data data buffer to accept the data from bus
* @param data_len read data length
* @param ack ack value for read command
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t data_len, int ack);
/**
* @brief Queue command for I2C master to generate a stop signal
* @note
* Only call this function in I2C master mode
* Call i2c_master_cmd_begin() to send all queued commands
*
* @param cmd_handle I2C cmd link
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_master_stop(i2c_cmd_handle_t cmd_handle);
/**
* @brief I2C master send queued commands.
* This function will trigger sending all queued commands.
* The task will be blocked until all the commands have been sent out.
* The I2C APIs are not thread-safe, if you want to use one I2C port in different tasks,
* you need to take care of the multi-thread issue.
* @note
* Only call this function in I2C master mode
*
* @param i2c_num I2C port number
* @param cmd_handle I2C command handler
* @param ticks_to_wait maximum wait ticks.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL Sending command error, slave doesn't ACK the transfer.
* - ESP_ERR_INVALID_STATE I2C driver not installed or not in master mode.
* - ESP_ERR_TIMEOUT Operation timeout because the bus is busy.
*/
esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, portBASE_TYPE ticks_to_wait);
/**
* @brief I2C slave write data to internal ringbuffer, when tx fifo empty, isr will fill the hardware
* fifo from the internal ringbuffer
* @note
* Only call this function in I2C slave mode
*
* @param i2c_num I2C port number
* @param data data pointer to write into internal buffer
* @param size data size
* @param ticks_to_wait Maximum waiting ticks
*
* @return
* - ESP_FAIL(-1) Parameter error
* - Others(>=0) The number of data bytes that pushed to the I2C slave buffer.
*/
int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t* data, int size, portBASE_TYPE ticks_to_wait);
/**
* @brief I2C slave read data from internal buffer. When I2C slave receive data, isr will copy received data
* from hardware rx fifo to internal ringbuffer. Then users can read from internal ringbuffer.
* @note
* Only call this function in I2C slave mode
*
* @param i2c_num I2C port number
* @param data data pointer to write into internal buffer
* @param max_size Maximum data size to read
* @param ticks_to_wait Maximum waiting ticks
*
* @return
* - ESP_FAIL(-1) Parameter error
* - Others(>=0) The number of data bytes that read from I2C slave buffer.
*/
int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, portBASE_TYPE ticks_to_wait);
/**
* @brief set I2C master clock period
*
* @param i2c_num I2C port number
* @param high_period clock cycle number during SCL is high level, high_period is a 14 bit value
* @param low_period clock cycle number during SCL is low level, low_period is a 14 bit value
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_set_period(i2c_port_t i2c_num, int high_period, int low_period);
/**
* @brief get I2C master clock period
*
* @param i2c_num I2C port number
* @param high_period pointer to get clock cycle number during SCL is high level, will get a 14 bit value
* @param low_period pointer to get clock cycle number during SCL is low level, will get a 14 bit value
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_get_period(i2c_port_t i2c_num, int* high_period, int* low_period);
/**
* @brief set I2C master start signal timing
*
* @param i2c_num I2C port number
* @param setup_time clock number between the falling-edge of SDA and rising-edge of SCL for start mark, it's a 10-bit value.
* @param hold_time clock num between the falling-edge of SDA and falling-edge of SCL for start mark, it's a 10-bit value.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_set_start_timing(i2c_port_t i2c_num, int setup_time, int hold_time);
/**
* @brief get I2C master start signal timing
*
* @param i2c_num I2C port number
* @param setup_time pointer to get setup time
* @param hold_time pointer to get hold time
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_get_start_timing(i2c_port_t i2c_num, int* setup_time, int* hold_time);
/**
* @brief set I2C master stop signal timing
*
* @param i2c_num I2C port number
* @param setup_time clock num between the rising-edge of SCL and the rising-edge of SDA, it's a 10-bit value.
* @param hold_time clock number after the STOP bit's rising-edge, it's a 14-bit value.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_set_stop_timing(i2c_port_t i2c_num, int setup_time, int hold_time);
/**
* @brief get I2C master stop signal timing
*
* @param i2c_num I2C port number
* @param setup_time pointer to get setup time.
* @param hold_time pointer to get hold time.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_get_stop_timing(i2c_port_t i2c_num, int* setup_time, int* hold_time);
/**
* @brief set I2C data signal timing
*
* @param i2c_num I2C port number
* @param sample_time clock number I2C used to sample data on SDA after the rising-edge of SCL, it's a 10-bit value
* @param hold_time clock number I2C used to hold the data after the falling-edge of SCL, it's a 10-bit value
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_set_data_timing(i2c_port_t i2c_num, int sample_time, int hold_time);
/**
* @brief get I2C data signal timing
*
* @param i2c_num I2C port number
* @param sample_time pointer to get sample time
* @param hold_time pointer to get hold time
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_get_data_timing(i2c_port_t i2c_num, int* sample_time, int* hold_time);
/**
* @brief set I2C data transfer mode
*
* @param i2c_num I2C port number
* @param tx_trans_mode I2C sending data mode
* @param rx_trans_mode I2C receving data mode
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_set_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t tx_trans_mode, i2c_trans_mode_t rx_trans_mode);
/**
* @brief get I2C data transfer mode
*
* @param i2c_num I2C port number
* @param tx_trans_mode pointer to get I2C sending data mode
* @param rx_trans_mode pointer to get I2C receiving data mode
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_get_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t *tx_trans_mode, i2c_trans_mode_t *rx_trans_mode);
#ifdef __cplusplus
}
#endif
#endif /*_DRIVER_I2C_H_*/

View File

@ -0,0 +1,380 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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.
#ifndef _DRIVER_I2S_H_
#define _DRIVER_I2S_H_
#include "esp_err.h"
#include <esp_types.h>
#include "soc/gpio_reg.h"
#include "soc/soc.h"
#include "soc/i2s_struct.h"
#include "soc/i2s_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/io_mux_reg.h"
#include "rom/gpio.h"
#include "esp_attr.h"
#include "esp_intr_alloc.h"
#include "driver/periph_ctrl.h"
#include "freertos/semphr.h"
#ifdef __cplusplus
extern "C" {
#endif
#define I2S_PIN_NO_CHANGE (-1)
/**
* @brief I2S bit width per sample.
*
*/
typedef enum {
I2S_BITS_PER_SAMPLE_8BIT = 8, /*!< I2S bits per sample: 8-bits*/
I2S_BITS_PER_SAMPLE_16BIT = 16, /*!< I2S bits per sample: 16-bits*/
I2S_BITS_PER_SAMPLE_24BIT = 24, /*!< I2S bits per sample: 24-bits*/
I2S_BITS_PER_SAMPLE_32BIT = 32, /*!< I2S bits per sample: 32-bits*/
} i2s_bits_per_sample_t;
/**
* @brief I2S communication standard format
*
*/
typedef enum {
I2S_COMM_FORMAT_I2S = 0x01, /*!< I2S communication format I2S*/
I2S_COMM_FORMAT_I2S_MSB = 0x02, /*!< I2S format MSB*/
I2S_COMM_FORMAT_I2S_LSB = 0x04, /*!< I2S format LSB*/
I2S_COMM_FORMAT_PCM = 0x08, /*!< I2S communication format PCM*/
I2S_COMM_FORMAT_PCM_SHORT = 0x10, /*!< PCM Short*/
I2S_COMM_FORMAT_PCM_LONG = 0x20, /*!< PCM Long*/
} i2s_comm_format_t;
/**
* @brief I2S channel format type
*/
typedef enum {
I2S_CHANNEL_FMT_RIGHT_LEFT = 0x00,
I2S_CHANNEL_FMT_ALL_RIGHT,
I2S_CHANNEL_FMT_ALL_LEFT,
I2S_CHANNEL_FMT_ONLY_RIGHT,
I2S_CHANNEL_FMT_ONLY_LEFT,
} i2s_channel_fmt_t;
/**
* @brief PDM sample rate ratio, measured in Hz.
*
*/
typedef enum {
PDM_SAMPLE_RATE_RATIO_64,
PDM_SAMPLE_RATE_RATIO_128,
} pdm_sample_rate_ratio_t;
/**
* @brief PDM PCM convter enable/disable.
*
*/
typedef enum {
PDM_PCM_CONV_ENABLE,
PDM_PCM_CONV_DISABLE,
} pdm_pcm_conv_t;
/**
* @brief I2S Peripheral, 0 & 1.
*
*/
typedef enum {
I2S_NUM_0 = 0x0, /*!< I2S 0*/
I2S_NUM_1 = 0x1, /*!< I2S 1*/
I2S_NUM_MAX,
} i2s_port_t;
/**
* @brief I2S Mode, defaut is I2S_MODE_MASTER | I2S_MODE_TX
*
*/
typedef enum {
I2S_MODE_MASTER = 1,
I2S_MODE_SLAVE = 2,
I2S_MODE_TX = 4,
I2S_MODE_RX = 8,
I2S_MODE_DAC_BUILT_IN = 16
} i2s_mode_t;
/**
* @brief I2S configuration parameters for i2s_param_config function
*
*/
typedef struct {
i2s_mode_t mode; /*!< I2S work mode*/
int sample_rate; /*!< I2S sample rate*/
i2s_bits_per_sample_t bits_per_sample; /*!< I2S bits per sample*/
i2s_channel_fmt_t channel_format; /*!< I2S channel format */
i2s_comm_format_t communication_format; /*!< I2S communication format */
int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */
int dma_buf_count; /*!< I2S DMA Buffer Count */
int dma_buf_len; /*!< I2S DMA Buffer Length */
} i2s_config_t;
/**
* @brief I2S event types
*
*/
typedef enum {
I2S_EVENT_DMA_ERROR,
I2S_EVENT_TX_DONE, /*!< I2S DMA finish sent 1 buffer*/
I2S_EVENT_RX_DONE, /*!< I2S DMA finish received 1 buffer*/
I2S_EVENT_MAX, /*!< I2S event max index*/
} i2s_event_type_t;
/**
* @brief Event structure used in I2S event queue
*
*/
typedef struct {
i2s_event_type_t type; /*!< I2S event type */
size_t size; /*!< I2S data size for I2S_DATA event*/
} i2s_event_t;
/**
* @brief I2S pin number for i2s_set_pin
*
*/
typedef struct {
int bck_io_num; /*!< BCK in out pin*/
int ws_io_num; /*!< WS in out pin*/
int data_out_num; /*!< DATA out pin*/
int data_in_num; /*!< DATA in pin*/
} i2s_pin_config_t;
typedef intr_handle_t i2s_isr_handle_t;
/**
* @brief Set I2S pin number
*
* @note
* Internal signal can be output to multiple GPIO pads
* Only one GPIO pad can connect with input signal
*
* @param i2s_num I2S_NUM_0 or I2S_NUM_1
*
* @param pin I2S Pin struct, or NULL for 2-channels, 8-bits DAC pin configuration (GPIO25 & GPIO26)
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin);
/**
* @brief i2s install and start driver
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param i2s_config I2S configurations - see i2s_config_t struct
*
* @param queue_size I2S event queue size/depth.
*
* @param i2s_queue I2S event queue handle, if set NULL, driver will not use an event queue.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void* i2s_queue);
/**
* @brief Uninstall I2S driver.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num);
/**
* @brief i2s read data buffer to i2s dma buffer
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param src source address to write
*
* @param size size of data (size in bytes)
*
* @param ticks_to_wait Write timeout
*
* @return number of written bytes
*/
int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t ticks_to_wait);
/**
* @brief i2s write data buffer to i2s dma buffer
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param dest destination address to read
*
* @param size size of data (size in bytes)
*
* @param ticks_to_wait Read timeout
*
* @return number of read bytes
*/
int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks_to_wait);
/**
* @brief i2s push 1 sample to i2s dma buffer, with the size parameter equal to one sample's size in bytes = bits_per_sample/8.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param sample destination address to write (depend on bits_per_sample, size of sample (in bytes) = 2*bits_per_sample/8)
*
* @param ticks_to_wait Push timeout
*
* @return number of push bytes
*/
int i2s_push_sample(i2s_port_t i2s_num, const char *sample, TickType_t ticks_to_wait);
/**
* @brief Pop 1 sample to i2s dma buffer, with the size parameter equal to one sample's size in bytes = bits_per_sample/8.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param sample destination address to write (depend on bits_per_sample, size of sample (in bytes) = 2*bits_per_sample/8)
*
* @param ticks_to_wait Pop timeout
*
* @return number of pop bytes
*/
int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait);
/**
* @brief Set clock rate used for I2S RX and TX
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param rate I2S clock (ex: 8000, 44100...)
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate);
/**
* @brief Start driver
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_start(i2s_port_t i2s_num);
/**
* @brief Stop driver
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_stop(i2s_port_t i2s_num);
/**
* @brief Set the TX DMA buffer contents to all zeroes
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num);
/***************************EXAMPLE**********************************
*
*
* ----------------EXAMPLE OF I2S SETTING ---------------------
* @code{c}
*
* #include "freertos/queue.h"
* #define I2S_INTR_NUM 17 //choose one interrupt number from soc.h
* int i2s_num = 0; //i2s port number
* i2s_config_t i2s_config = {
* .mode = I2S_MODE_MASTER | I2S_MODE_TX,
* .sample_rate = 44100,
* .bits_per_sample = 16, //16, 32
* .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //format LEFT_RIGHT
* .communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
* .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
* .dma_buf_count = 8,
* .dma_buf_len = 64
* };
*
* i2s_pin_config_t pin_config = {
* .bck_io_num = 26,
* .ws_io_num = 25,
* .data_out_num = 22,
* .data_in_num = I2S_PIN_NO_CHANGE
* };
*
* i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
*
* i2s_set_pin(i2s_num, &pin_config);
*
* i2s_set_sample_rates(i2s_num, 22050); //set sample rates
*
*
* i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
*@endcode
*
* ----------------EXAMPLE USING I2S WITH DAC ---------------------
* @code{c}
*
* #include "freertos/queue.h"
* #define I2S_INTR_NUM 17 //choose one interrupt number from soc.h
* int i2s_num = 0; //i2s port number
* i2s_config_t i2s_config = {
* .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
* .sample_rate = 44100,
* .bits_per_sample = 8, // Only 8-bit DAC support
* .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //
* .communication_format = I2S_COMM_FORMAT_I2S_MSB,
* .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
* .dma_buf_count = 8,
* .dma_buf_len = 64
* };
*
*
* i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
*
* i2s_set_pin(i2s_num, NULL); //for internal DAC
*
* i2s_set_sample_rates(i2s_num, 22050); //set sample rates
*
* i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
*@endcode
*-----------------------------------------------------------------------------*
***************************END OF EXAMPLE**********************************/
#ifdef __cplusplus
}
#endif
#endif /* _DRIVER_I2S_H_ */

View File

@ -253,7 +253,7 @@ int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty, ledc_duty_direction_t gradule_direction,
esp_err_t ledc_set_fade(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty, ledc_duty_direction_t gradule_direction,
uint32_t step_num, uint32_t duty_cyle_num, uint32_t duty_scale);
/**
@ -354,7 +354,7 @@ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel);
* - ESP_OK Success
*
*/
esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint32_t timer_idx);
esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t timer_idx);
/***************************EXAMPLE**********************************
*
@ -391,7 +391,7 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint
*
* ----------------EXAMPLE OF SETTING DUTY --- -----------------
* @code{c}
* uint32_t ledc_channel = LEDC_CHANNEL_0; //LEDC channel(0-73)
* ledc_channel_t ledc_channel = LEDC_CHANNEL_0; //LEDC channel(0-73)
* uint32_t duty = 2000; //duty range is 0 ~ ((2**bit_num)-1)
* LEDC_set_duty(LEDC_HIGH_SPEED_MODE, ledc_channel, duty); //set speed mode, channel, and duty.
* ledc_update_duty(LEDC_HIGH_SPEED_MODE, ledc_channel); //after set duty, we need to call ledc_update_duty to update the settings.

View File

@ -524,7 +524,9 @@ esp_err_t rmt_set_err_intr_en(rmt_channel_t channel, bool en);
esp_err_t rmt_set_tx_intr_en(rmt_channel_t channel, bool en);
/**
* @brief Set RMT TX event interrupt enable
* @brief Set RMT TX threshold event interrupt enable
*
* Causes an interrupt when a threshold number of items have been transmitted.
*
* @param channel RMT channel (0 - 7)
*
@ -536,7 +538,7 @@ esp_err_t rmt_set_tx_intr_en(rmt_channel_t channel, bool en);
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_evt_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh);
esp_err_t rmt_set_tx_thr_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh);
/**
* @brief Set RMT pins

View File

@ -23,6 +23,7 @@ extern "C" {
#include "soc/uart_reg.h"
#include "soc/uart_struct.h"
#include "esp_err.h"
#include "esp_intr_alloc.h"
#include "driver/periph_ctrl.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
@ -129,6 +130,7 @@ typedef enum {
UART_PARITY_ERR, /*!< UART RX parity event*/
UART_DATA_BREAK, /*!< UART TX data and break event*/
UART_EVENT_MAX, /*!< UART event max index*/
UART_PATTERN_DET, /*!< UART pattern detected */
} uart_event_type_t;
/**
@ -139,6 +141,8 @@ typedef struct {
size_t size; /*!< UART data size for UART_DATA event*/
} uart_event_t;
typedef intr_handle_t uart_isr_handle_t;
/**
* @brief Set UART data bits.
*
@ -372,12 +376,14 @@ esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh);
* @param arg parameter for handler function
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
* be returned here.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags);
esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags, uart_isr_handle_t *handle);
/**
@ -467,11 +473,12 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_
* We can find the information of INUM and interrupt level in soc.h.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param rx_buffer_size UART RX ring buffer size
* @param rx_buffer_size UART RX ring buffer size, rx_buffer_size should be greater than UART_FIFO_LEN.
* @param tx_buffer_size UART TX ring buffer size.
* If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out..
* @param queue_size UART event queue size/depth.
* @param uart_queue UART event queue handle, if set NULL, driver will not use an event queue.
* @param uart_queue UART event queue handle (out param). On success, a new queue handle is written here to provide
* access to UART events. If set to NULL, driver will not use an event queue.
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
*
@ -479,7 +486,7 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, void* uart_queue, int intr_alloc_flags);
esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, QueueHandle_t* uart_queue, int intr_alloc_flags);
/**
* @brief Uninstall UART driver.
@ -588,6 +595,48 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickTyp
*/
esp_err_t uart_flush(uart_port_t uart_num);
/**
* @brief UART get RX ring buffer cached data length
*
* @param uart_num UART port number.
* @param size Pointer of size_t to accept cached data length
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t* size);
/**
* @brief UART disable pattern detect function.
* Designed for applications like 'AT commands'.
* When the hardware detect a series of one same character, the interrupt will be triggered.
*
* @param uart_num UART port number.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_disable_pattern_det_intr(uart_port_t uart_num);
/**
* @brief UART enable pattern detect function.
* Designed for applications like 'AT commands'.
* When the hardware detect a series of one same character, the interrupt will be triggered.
*
* @param uart_num UART port number.
* @param pattern_chr character of the pattern
* @param chr_num number of the character, 8bit value.
* @param chr_tout timeout of the interval between each pattern characters, 24bit value, unit is APB(80Mhz) clock cycle.
* @param post_idle idle time after the last pattern character, 24bit value, unit is APB(80Mhz) clock cycle.
* @param pre_idle idle time before the first pattern character, 24bit value, unit is APB(80Mhz) clock cycle.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_enable_pattern_det_intr(uart_port_t uart_num, char pattern_chr, uint8_t chr_num, int chr_tout, int post_idle, int pre_idle);
/***************************EXAMPLE**********************************
*
*
@ -599,7 +648,7 @@ esp_err_t uart_flush(uart_port_t uart_num);
* //a. Set UART parameter
* int uart_num = 0; //uart port number
* uart_config_t uart_config = {
* .baud_rate = UART_BITRATE_115200, //baudrate
* .baud_rate = 115200, //baudrate
* .data_bits = UART_DATA_8_BITS, //data bit mode
* .parity = UART_PARITY_DISABLE, //parity mode
* .stop_bits = UART_STOP_BITS_1, //stop bit mode
@ -658,7 +707,7 @@ esp_err_t uart_flush(uart_port_t uart_num);
* //Set UART1 pins(TX: IO16, RX: IO17, RTS: IO18, CTS: IO19)
* uart_set_pin(uart_num, 16, 17, 18, 19);
* //Install UART driver( We don't need an event queue here)
* uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, 17, NULL, RINGBUF_TYPE_BYTEBUF);
* uart_driver_install(uart_num, 1024 * 2, 1024*4, 0, NULL, 0);
* uint8_t data[1000];
* while(1) {
* //Read data from UART
@ -692,7 +741,6 @@ esp_err_t uart_flush(uart_port_t uart_num);
* ESP_LOGI(TAG,"data, len: %d", event.size);
* int len = uart_read_bytes(uart_num, dtmp, event.size, 10);
* ESP_LOGI(TAG, "uart read: %d", len);
uart_write_bytes(uart_num, (const char*)dtmp, len);
* break;
* //Event of HW FIFO overflow detected
* case UART_FIFO_OVF:

View File

@ -44,7 +44,7 @@ esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_
return ESP_OK;
}
static esp_err_t ledc_duty_config(ledc_mode_t speed_mode, uint32_t channel_num, uint32_t hpoint_val, uint32_t duty_val,
static esp_err_t ledc_duty_config(ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t hpoint_val, uint32_t duty_val,
uint32_t duty_direction, uint32_t duty_num, uint32_t duty_cycle, uint32_t duty_scale)
{
portENTER_CRITICAL(&ledc_spinlock);
@ -58,7 +58,7 @@ static esp_err_t ledc_duty_config(ledc_mode_t speed_mode, uint32_t channel_num,
return ESP_OK;
}
esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint32_t timer_idx)
esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t timer_idx)
{
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
LEDC_CHECK(timer_idx <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
@ -239,7 +239,7 @@ esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idl
portEXIT_CRITICAL(&ledc_spinlock);
return ESP_OK;
}
esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty, ledc_duty_direction_t fade_direction,
esp_err_t ledc_set_fade(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty, ledc_duty_direction_t fade_direction,
uint32_t step_num, uint32_t duty_cyle_num, uint32_t duty_scale)
{
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);

View File

@ -341,7 +341,7 @@ esp_err_t rmt_set_tx_intr_en(rmt_channel_t channel, bool en)
return ESP_OK;
}
esp_err_t rmt_set_evt_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh)
esp_err_t rmt_set_tx_thr_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh)
{
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
RMT_CHECK(evt_thresh < 256, "RMT EVT THRESH ERR", ESP_ERR_INVALID_ARG);
@ -380,10 +380,16 @@ esp_err_t rmt_config(rmt_config_t* rmt_param)
uint8_t gpio_num = rmt_param->gpio_num;
uint8_t mem_cnt = rmt_param->mem_block_num;
int clk_div = rmt_param->clk_div;
uint32_t carrier_freq_hz = rmt_param->tx_config.carrier_freq_hz;
bool carrier_en = rmt_param->tx_config.carrier_en;
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
RMT_CHECK(GPIO_IS_VALID_GPIO(gpio_num), RMT_GPIO_ERROR_STR, ESP_ERR_INVALID_ARG);
RMT_CHECK((mem_cnt + channel <= 8 && mem_cnt > 0), RMT_MEM_CNT_ERROR_STR, ESP_ERR_INVALID_ARG);
RMT_CHECK((clk_div > 0), RMT_CLK_DIV_ERROR_STR, ESP_ERR_INVALID_ARG);
if (mode == RMT_MODE_TX) {
RMT_CHECK((!carrier_en || carrier_freq_hz > 0), "RMT carrier frequency can't be zero", ESP_ERR_INVALID_ARG);
}
periph_module_enable(PERIPH_RMT_MODULE);
RMT.conf_ch[channel].conf0.div_cnt = clk_div;
@ -397,7 +403,6 @@ esp_err_t rmt_config(rmt_config_t* rmt_param)
if(mode == RMT_MODE_TX) {
uint32_t rmt_source_clk_hz = 0;
uint32_t carrier_freq_hz = rmt_param->tx_config.carrier_freq_hz;
uint16_t carrier_duty_percent = rmt_param->tx_config.carrier_duty_percent;
uint8_t carrier_level = rmt_param->tx_config.carrier_level;
uint8_t idle_level = rmt_param->tx_config.idle_level;
@ -416,16 +421,23 @@ esp_err_t rmt_config(rmt_config_t* rmt_param)
portEXIT_CRITICAL(&rmt_spinlock);
/*Set carrier*/
uint32_t duty_div, duty_h, duty_l;
duty_div = rmt_source_clk_hz / carrier_freq_hz;
duty_h = duty_div * carrier_duty_percent / 100;
duty_l = duty_div - duty_h;
RMT.conf_ch[channel].conf0.carrier_out_lv = carrier_level;
RMT.carrier_duty_ch[channel].high = duty_h;
RMT.carrier_duty_ch[channel].low = duty_l;
RMT.conf_ch[channel].conf0.carrier_en = rmt_param->tx_config.carrier_en;
RMT.conf_ch[channel].conf0.carrier_en = carrier_en;
if (carrier_en) {
uint32_t duty_div, duty_h, duty_l;
duty_div = rmt_source_clk_hz / carrier_freq_hz;
duty_h = duty_div * carrier_duty_percent / 100;
duty_l = duty_div - duty_h;
RMT.conf_ch[channel].conf0.carrier_out_lv = carrier_level;
RMT.carrier_duty_ch[channel].high = duty_h;
RMT.carrier_duty_ch[channel].low = duty_l;
} else {
RMT.conf_ch[channel].conf0.carrier_out_lv = 0;
RMT.carrier_duty_ch[channel].high = 0;
RMT.carrier_duty_ch[channel].low = 0;
}
ESP_LOGD(RMT_TAG, "Rmt Tx Channel %u|Gpio %u|Sclk_Hz %u|Div %u|Carrier_Hz %u|Duty %u",
channel, gpio_num, rmt_source_clk_hz, clk_div, carrier_freq_hz, carrier_duty_percent);
channel, gpio_num, rmt_source_clk_hz, clk_div, carrier_freq_hz, carrier_duty_percent);
}
else if(RMT_MODE_RX == mode) {
uint8_t filter_cnt = rmt_param->rx_config.filter_ticks_thresh;
@ -612,7 +624,7 @@ esp_err_t rmt_driver_uninstall(rmt_channel_t channel)
rmt_set_rx_intr_en(channel, 0);
rmt_set_err_intr_en(channel, 0);
rmt_set_tx_intr_en(channel, 0);
rmt_set_evt_intr_en(channel, 0, 0xffff);
rmt_set_tx_thr_intr_en(channel, 0, 0xffff);
if(p_rmt_obj[channel]->tx_sem) {
vSemaphoreDelete(p_rmt_obj[channel]->tx_sem);
p_rmt_obj[channel]->tx_sem = NULL;
@ -685,7 +697,7 @@ esp_err_t rmt_write_items(rmt_channel_t channel, rmt_item32_t* rmt_item, int ite
RMT.apb_conf.mem_tx_wrap_en = 1;
len_rem -= item_block_len;
RMT.conf_ch[channel].conf1.tx_conti_mode = 0;
rmt_set_evt_intr_en(channel, 1, item_sub_len);
rmt_set_tx_thr_intr_en(channel, 1, item_sub_len);
p_rmt->tx_data = rmt_item + item_block_len;
p_rmt->tx_len_rem = len_rem;
p_rmt->tx_offset = 0;

View File

@ -59,6 +59,7 @@ typedef struct {
QueueHandle_t xQueueUart; /*!< UART queue handler*/
intr_handle_t intr_handle; /*!< UART interrupt handle*/
//rx parameters
int rx_buffered_len; /*!< UART cached data length */
SemaphoreHandle_t rx_mux; /*!< UART RX data mutex*/
int rx_buf_size; /*!< RX ring buffer size */
RingbufHandle_t rx_ring_buf; /*!< RX ring buffer handler*/
@ -260,22 +261,38 @@ esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask)
return ESP_OK;
}
esp_err_t uart_enable_pattern_det_intr(uart_port_t uart_num, char pattern_chr, uint8_t chr_num, int chr_tout, int post_idle, int pre_idle)
{
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
UART_CHECK(chr_tout >= 0 && chr_tout <= UART_RX_GAP_TOUT_V, "uart pattern set error\n", ESP_FAIL);
UART_CHECK(post_idle >= 0 && post_idle <= UART_POST_IDLE_NUM_V, "uart pattern set error\n", ESP_FAIL);
UART_CHECK(pre_idle >= 0 && pre_idle <= UART_PRE_IDLE_NUM_V, "uart pattern set error\n", ESP_FAIL);
UART[uart_num]->at_cmd_char.data = pattern_chr;
UART[uart_num]->at_cmd_char.char_num = chr_num;
UART[uart_num]->at_cmd_gaptout.rx_gap_tout = chr_tout;
UART[uart_num]->at_cmd_postcnt.post_idle_num = post_idle;
UART[uart_num]->at_cmd_precnt.pre_idle_num = pre_idle;
return uart_enable_intr_mask(uart_num, UART_AT_CMD_CHAR_DET_INT_ENA_M);
}
esp_err_t uart_disable_pattern_det_intr(uart_port_t uart_num)
{
return uart_disable_intr_mask(uart_num, UART_AT_CMD_CHAR_DET_INT_ENA_M);
}
esp_err_t uart_enable_rx_intr(uart_port_t uart_num)
{
uart_enable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
return ESP_OK;
return uart_enable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
}
esp_err_t uart_disable_rx_intr(uart_port_t uart_num)
{
uart_disable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
return ESP_OK;
return uart_disable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
}
esp_err_t uart_disable_tx_intr(uart_port_t uart_num)
{
uart_disable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA);
return ESP_OK;
return uart_disable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA);
}
esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh)
@ -290,21 +307,21 @@ esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh)
return ESP_OK;
}
esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags)
esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags, uart_isr_handle_t *handle)
{
int ret;
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
switch(uart_num) {
case UART_NUM_1:
ret=esp_intr_alloc(ETS_UART1_INTR_SOURCE, intr_alloc_flags, fn, arg, &p_uart_obj[uart_num]->intr_handle);
ret=esp_intr_alloc(ETS_UART1_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
break;
case UART_NUM_2:
ret=esp_intr_alloc(ETS_UART2_INTR_SOURCE, intr_alloc_flags, fn, arg, &p_uart_obj[uart_num]->intr_handle);
ret=esp_intr_alloc(ETS_UART2_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
break;
case UART_NUM_0:
default:
ret=esp_intr_alloc(ETS_UART0_INTR_SOURCE, intr_alloc_flags, fn, arg, &p_uart_obj[uart_num]->intr_handle);
ret=esp_intr_alloc(ETS_UART0_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
break;
}
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
@ -370,6 +387,7 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r
if(rx_io_num >= 0) {
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[rx_io_num], PIN_FUNC_GPIO);
gpio_set_pull_mode(rx_io_num, GPIO_PULLUP_ONLY);
gpio_set_direction(rx_io_num, GPIO_MODE_INPUT);
gpio_matrix_in(rx_io_num, rx_sig, 0);
}
@ -380,6 +398,7 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r
}
if(cts_io_num >= 0) {
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cts_io_num], PIN_FUNC_GPIO);
gpio_set_pull_mode(cts_io_num, GPIO_PULLUP_ONLY);
gpio_set_direction(cts_io_num, GPIO_MODE_INPUT);
gpio_matrix_in(cts_io_num, cts_sig, 0);
}
@ -447,7 +466,7 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_
}
UART[uart_num]->int_ena.val = intr_conf->intr_enable_mask;
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
return ESP_FAIL;
return ESP_OK;
}
//internal isr handler for default driver code.
@ -595,6 +614,9 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param)
p_uart->rx_buffer_full_flg = true;
uart_event.type = UART_BUFFER_FULL;
} else {
UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
p_uart->rx_buffered_len += p_uart->rx_stash_len;
UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
uart_event.type = UART_DATA;
}
if(HPTaskAwoken == pdTRUE) {
@ -618,11 +640,11 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param)
} else if(uart_intr_status & UART_BRK_DET_INT_ST_M) {
uart_reg->int_clr.brk_det = 1;
uart_event.type = UART_BREAK;
} else if(uart_intr_status & UART_PARITY_ERR_INT_ST_M ) {
uart_reg->int_clr.parity_err = 1;
uart_event.type = UART_FRAME_ERR;
} else if(uart_intr_status & UART_FRM_ERR_INT_ST_M) {
uart_reg->int_clr.frm_err = 1;
uart_event.type = UART_FRAME_ERR;
} else if(uart_intr_status & UART_PARITY_ERR_INT_ST_M) {
uart_reg->int_clr.parity_err = 1;
uart_event.type = UART_PARITY_ERR;
} else if(uart_intr_status & UART_TX_BRK_DONE_INT_ST_M) {
UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
@ -647,6 +669,9 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param)
uart_reg->int_ena.tx_brk_idle_done = 0;
uart_reg->int_clr.tx_brk_idle_done = 1;
UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
} else if(uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M) {
uart_reg->int_clr.at_cmd_char_det = 1;
uart_event.type = UART_PATTERN_DET;
} else if(uart_intr_status & UART_TX_DONE_INT_ST_M) {
UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
uart_reg->int_ena.tx_done = 0;
@ -656,8 +681,7 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param)
if(HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR() ;
}
}
else {
} else {
uart_reg->int_clr.val = uart_intr_status; /*simply clear all other intr status*/
uart_event.type = UART_EVENT_MAX;
}
@ -833,6 +857,9 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickTyp
p_uart_obj[uart_num]->rx_cur_remain = size;
} else {
xSemaphoreGive(p_uart_obj[uart_num]->rx_mux);
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
p_uart_obj[uart_num]->rx_buffered_len -= copy_len;
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
return copy_len;
}
}
@ -853,6 +880,9 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickTyp
if(p_uart_obj[uart_num]->rx_buffer_full_flg) {
BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1);
if(res == pdTRUE) {
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
p_uart_obj[uart_num]->rx_buffered_len += p_uart_obj[uart_num]->rx_stash_len;
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
p_uart_obj[uart_num]->rx_buffer_full_flg = false;
uart_enable_rx_intr(p_uart_obj[uart_num]->uart_num);
}
@ -860,9 +890,20 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickTyp
}
}
xSemaphoreGive(p_uart_obj[uart_num]->rx_mux);
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
p_uart_obj[uart_num]->rx_buffered_len -= copy_len;
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
return copy_len;
}
esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t* size)
{
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL);
*size = p_uart_obj[uart_num]->rx_buffered_len;
return ESP_OK;
}
esp_err_t uart_flush(uart_port_t uart_num)
{
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
@ -873,10 +914,13 @@ esp_err_t uart_flush(uart_port_t uart_num)
//rx sem protect the ring buffer read related functions
xSemaphoreTake(p_uart->rx_mux, (portTickType)portMAX_DELAY);
esp_intr_disable(p_uart->intr_handle);
uart_disable_rx_intr(p_uart_obj[uart_num]->uart_num);
while(true) {
if(p_uart->rx_head_ptr) {
vRingbufferReturnItem(p_uart->rx_ring_buf, p_uart->rx_head_ptr);
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
p_uart_obj[uart_num]->rx_buffered_len -= p_uart->rx_cur_remain;
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
p_uart->rx_ptr = NULL;
p_uart->rx_cur_remain = 0;
p_uart->rx_head_ptr = NULL;
@ -885,47 +929,33 @@ esp_err_t uart_flush(uart_port_t uart_num)
if(data == NULL) {
break;
}
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
p_uart_obj[uart_num]->rx_buffered_len -= size;
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
vRingbufferReturnItem(p_uart->rx_ring_buf, data);
if(p_uart_obj[uart_num]->rx_buffer_full_flg) {
BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1);
if(res == pdTRUE) {
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
p_uart_obj[uart_num]->rx_buffered_len += p_uart_obj[uart_num]->rx_stash_len;
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
p_uart_obj[uart_num]->rx_buffer_full_flg = false;
}
}
}
p_uart->rx_ptr = NULL;
p_uart->rx_cur_remain = 0;
p_uart->rx_head_ptr = NULL;
esp_intr_enable(p_uart->intr_handle);
xSemaphoreGive(p_uart->rx_mux);
if(p_uart->tx_buf_size > 0) {
xSemaphoreTake(p_uart->tx_mux, (portTickType)portMAX_DELAY);
esp_intr_disable(p_uart->intr_handle);
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
UART[uart_num]->int_ena.txfifo_empty = 0;
UART[uart_num]->int_clr.txfifo_empty = 1;
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
do {
data = (uint8_t*) xRingbufferReceive(p_uart->tx_ring_buf, &size, (portTickType) 0);
if(data == NULL) {
break;
}
vRingbufferReturnItem(p_uart->rx_ring_buf, data);
} while(1);
p_uart->tx_brk_flg = 0;
p_uart->tx_brk_len = 0;
p_uart->tx_head = NULL;
p_uart->tx_len_cur = 0;
p_uart->tx_len_tot = 0;
p_uart->tx_ptr = NULL;
p_uart->tx_waiting_brk = 0;
p_uart->tx_waiting_fifo = false;
esp_intr_enable(p_uart->intr_handle);
xSemaphoreGive(p_uart->tx_mux);
}
uart_reset_fifo(uart_num);
uart_enable_rx_intr(p_uart_obj[uart_num]->uart_num);
xSemaphoreGive(p_uart->rx_mux);
return ESP_OK;
}
esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, void* uart_queue, int intr_alloc_flags)
esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, QueueHandle_t *uart_queue, int intr_alloc_flags)
{
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
UART_CHECK((rx_buffer_size > 0), "uart rx buffer length error", ESP_FAIL);
UART_CHECK((rx_buffer_size > UART_FIFO_LEN), "uart rx buffer length error(>128)", ESP_FAIL);
if(p_uart_obj[uart_num] == NULL) {
p_uart_obj[uart_num] = (uart_obj_t*) malloc(sizeof(uart_obj_t));
if(p_uart_obj[uart_num] == NULL) {
@ -946,10 +976,11 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b
p_uart_obj[uart_num]->tx_brk_flg = 0;
p_uart_obj[uart_num]->tx_brk_len = 0;
p_uart_obj[uart_num]->tx_waiting_brk = 0;
p_uart_obj[uart_num]->rx_buffered_len = 0;
if(uart_queue) {
p_uart_obj[uart_num]->xQueueUart = xQueueCreate(queue_size, sizeof(uart_event_t));
*((QueueHandle_t*) uart_queue) = p_uart_obj[uart_num]->xQueueUart;
*uart_queue = p_uart_obj[uart_num]->xQueueUart;
ESP_LOGI(UART_TAG, "queue free spaces: %d", uxQueueSpacesAvailable(p_uart_obj[uart_num]->xQueueUart));
} else {
p_uart_obj[uart_num]->xQueueUart = NULL;
@ -971,7 +1002,7 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b
ESP_LOGE(UART_TAG, "UART driver already installed");
return ESP_FAIL;
}
uart_isr_register(uart_num, uart_rx_intr_handler_default, p_uart_obj[uart_num], intr_alloc_flags);
uart_isr_register(uart_num, uart_rx_intr_handler_default, p_uart_obj[uart_num], intr_alloc_flags, &p_uart_obj[uart_num]->intr_handle);
uart_intr_config_t uart_intr = {
.intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M
| UART_RXFIFO_TOUT_INT_ENA_M

View File

@ -42,3 +42,15 @@ void IRAM_ATTR esp_cpu_unstall(int cpu_id)
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_PROCPU_C0_M);
}
}
bool IRAM_ATTR esp_cpu_in_ocd_debug_mode()
{
#if CONFIG_ESP32_DEBUG_OCDAWARE
int dcr;
int reg=0x10200C; //DSRSET register
asm("rer %0,%1":"=r"(dcr):"r"(reg));
return (dcr&0x1);
#else
return false; // Always return false if "OCD aware" is disabled
#endif
}

View File

@ -107,17 +107,15 @@ typedef struct {
* WiFi NVS structure etc, this WiFi also start WiFi task
*
* @attention 1. This API must be called before all other WiFi API can be called
* @attention 2. Generally we should init event_q in *config, WiFi driver will post the event
* to this queue when event happens, such as, when station connects to WiFi, WiFi driver
* will post station connected event to this queue. If the queue is not initialized, WiFi
* will not post any events
* @attention 2. event_handler field in cfg should be set to a valid event handler function.
* In most cases, use the WIFI_INIT_CONFIG_DEFAULT macro which sets esp_event_send().
*
* @param config provide WiFi init configuration
*
* @return
* - ESP_OK: succeed
* - ESP_ERR_WIFI_NO_MEM: out of memory
* - others: refer to error code esp_err.h
* - others: refer to error code esp_err.h
*/
esp_err_t esp_wifi_init(wifi_init_config_t *config);

View File

@ -96,7 +96,7 @@ typedef enum {
} wifi_second_chan_t;
typedef struct {
char *ssid; /**< SSID of AP */
uint8_t *ssid; /**< SSID of AP */
uint8_t *bssid; /**< MAC address of AP */
uint8_t channel; /**< channel, scan the specific channel */
bool show_hidden; /**< enable to scan AP whose SSID is hidden */
@ -126,8 +126,8 @@ typedef enum {
} wifi_bandwidth_t;
typedef struct {
char ssid[32]; /**< SSID of ESP32 soft-AP */
char password[64]; /**< Password of ESP32 soft-AP */
uint8_t ssid[32]; /**< SSID of ESP32 soft-AP */
uint8_t password[64]; /**< Password of ESP32 soft-AP */
uint8_t ssid_len; /**< Length of SSID. If softap_config.ssid_len==0, check the SSID until there is a termination character; otherwise, set the SSID length according to softap_config.ssid_len. */
uint8_t channel; /**< Channel of ESP32 soft-AP */
wifi_auth_mode_t authmode; /**< Auth mode of ESP32 soft-AP. Do not support AUTH_WEP in soft-AP mode */
@ -137,8 +137,8 @@ typedef struct {
} wifi_ap_config_t;
typedef struct {
char ssid[32]; /**< SSID of target AP*/
char password[64]; /**< password of target AP*/
uint8_t ssid[32]; /**< SSID of target AP*/
uint8_t password[64]; /**< password of target AP*/
bool bssid_set; /**< whether set MAC address of target AP or not. Generally, station_config.bssid_set needs to be 0; and it needs to be 1 only when users need to check the MAC address of the AP.*/
uint8_t bssid[6]; /**< MAC address of target AP*/
} wifi_sta_config_t;
@ -215,7 +215,7 @@ typedef struct {
typedef struct {
wifi_pkt_rx_ctrl_t rx_ctrl;
char payload[0]; /**< ieee80211 packet buff, The length of payload is described by sig_len */
uint8_t payload[0]; /**< ieee80211 packet buff, The length of payload is described by sig_len */
} wifi_promiscuous_pkt_t;
/**

View File

@ -26,6 +26,16 @@
#define WSR(reg, newval) asm volatile ("wsr %0, " #reg : : "r" (newval));
#define XSR(reg, swapval) asm volatile ("xsr %0, " #reg : "+r" (swapval));
/** @brief Read current stack pointer address
*
*/
static inline void *get_sp()
{
void *sp;
asm volatile ("mov %0, sp;" : "=r" (sp));
return sp;
}
/* Return true if the CPU is in an interrupt context
(PS.UM == 0)
*/
@ -94,4 +104,13 @@ void esp_cpu_stall(int cpu_id);
*/
void esp_cpu_unstall(int cpu_id);
/**
* @brief Returns true if a JTAG debugger is attached to CPU
* OCD (on chip debug) port.
*
* @note If "Make exception and panic handlers JTAG/OCD aware"
* is disabled, this function always returns false.
*/
bool esp_cpu_in_ocd_debug_mode();
#endif

View File

@ -261,6 +261,8 @@
#define I2C_RXFIFO_FULL_THRHD_V 0x1F
#define I2C_RXFIFO_FULL_THRHD_S 0
#define I2C_DATA_APB_REG(i) (0x60013000 + (i) * 0x14000 + 0x001c)
#define I2C_DATA_REG(i) (REG_I2C_BASE(i) + 0x001c)
/* I2C_FIFO_RDATA : RO ;bitpos:[7:0] ;default: 8'b0 ; */
/*description: The register represent the byte data read from rxfifo when use apb fifo access*/

View File

@ -16,7 +16,7 @@
typedef volatile struct {
union {
struct {
uint32_t scl_low_period:14; /*This register is used to configure the low level width of SCL clock.*/
uint32_t period:14; /*This register is used to configure the low level width of SCL clock.*/
uint32_t reserved14: 18;
};
uint32_t val;
@ -58,7 +58,7 @@ typedef volatile struct {
} status_reg;
union {
struct {
uint32_t tout: 20; /*This register is used to configure the max clock number of receiving a data.*/
uint32_t tout: 20; /*This register is used to configure the max clock number of receiving a data, unit: APB clock cycle.*/
uint32_t reserved20:12;
};
uint32_t val;
@ -282,7 +282,7 @@ typedef volatile struct {
uint32_t reserved_f4;
uint32_t date; /**/
uint32_t reserved_fc;
uint32_t fifo_start_addr; /*This the start address for ram when use apb nonfifo access.*/
uint32_t ram_data[32]; /*This the start address for ram when use apb nonfifo access.*/
} i2c_dev_t;
extern i2c_dev_t I2C0;
extern i2c_dev_t I2C1;

View File

@ -636,7 +636,7 @@ int esp_intr_get_cpu(intr_handle_t handle)
//Muxing an interrupt source to interrupt 6, 7, 11, 15, 16 or 29 cause the interrupt to effectively be disabled.
#define INT_MUX_DISABLED_INTNO 6
esp_err_t esp_intr_enable(intr_handle_t handle)
esp_err_t IRAM_ATTR esp_intr_enable(intr_handle_t handle)
{
if (!handle) return ESP_ERR_INVALID_ARG;
portENTER_CRITICAL(&spinlock);
@ -659,7 +659,7 @@ esp_err_t esp_intr_enable(intr_handle_t handle)
return ESP_OK;
}
esp_err_t esp_intr_disable(intr_handle_t handle)
esp_err_t IRAM_ATTR esp_intr_disable(intr_handle_t handle)
{
if (!handle) return ESP_ERR_INVALID_ARG;
portENTER_CRITICAL(&spinlock);

View File

@ -99,7 +99,7 @@ SECTIONS
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
*(.dynbss)
KEEP(*(.bss))
*(.bss)
*(.bss.*)
*(.share.mem)
*(.gnu.linkonce.b.*)
@ -111,17 +111,17 @@ SECTIONS
.dram0.data :
{
_data_start = ABSOLUTE(.);
KEEP(*(.data))
KEEP(*(.data.*))
KEEP(*(.gnu.linkonce.d.*))
KEEP(*(.data1))
KEEP(*(.sdata))
KEEP(*(.sdata.*))
KEEP(*(.gnu.linkonce.s.*))
KEEP(*(.sdata2))
KEEP(*(.sdata2.*))
KEEP(*(.gnu.linkonce.s2.*))
KEEP(*(.jcr))
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
*(.data1)
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
*(.jcr)
*(.dram1 .dram1.*)
*libesp32.a:panic.o(.rodata .rodata.*)
_data_end = ABSOLUTE(.);

View File

@ -36,7 +36,7 @@
/*
Panic handlers; these get called when an unhandled exception occurs or the assembly-level
task switching / interrupt code runs into an unrecoverable error. The default task stack
overflow handler also is in here.
overflow handler and abort handler are also in here.
*/
/*
@ -95,15 +95,29 @@ inline static void panicPutHex(int a) { }
inline static void panicPutDec(int a) { }
#endif
void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )
{
panicPutStr("***ERROR*** A stack overflow in task ");
panicPutStr((char *)pcTaskName);
panicPutStr(" has been detected.\r\n");
configASSERT(0);
abort();
}
static bool abort_called;
void abort()
{
#if !CONFIG_ESP32_PANIC_SILENT_REBOOT
ets_printf("abort() was called at PC 0x%08x\n", (intptr_t)__builtin_return_address(0) - 3);
#endif
abort_called = true;
while(1) {
__asm__ ("break 0,0");
*((int*) 0) = 0;
}
}
static const char *edesc[] = {
"IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError",
"Level1Interrupt", "Alloca", "IntegerDivideByZero", "PCValue",
@ -118,7 +132,7 @@ static const char *edesc[] = {
};
void commonErrorHandler(XtExcFrame *frame);
static void commonErrorHandler(XtExcFrame *frame);
//The fact that we've panic'ed probably means the other CPU is now running wild, possibly
//messing up the serial output, so we stall it here.
@ -127,19 +141,6 @@ static void haltOtherCore()
esp_cpu_stall( xPortGetCoreID() == 0 ? 1 : 0 );
}
//Returns true when a debugger is attached using JTAG.
static int inOCDMode()
{
#if CONFIG_ESP32_DEBUG_OCDAWARE
int dcr;
int reg = 0x10200C; //DSRSET register
asm("rer %0,%1":"=r"(dcr):"r"(reg));
return (dcr & 0x1);
#else
return 0; //Always return no debugger is attached.
#endif
}
void panicHandler(XtExcFrame *frame)
{
int *regs = (int *)frame;
@ -165,7 +166,7 @@ void panicHandler(XtExcFrame *frame)
panicPutStr(reason);
panicPutStr(")\r\n");
if (inOCDMode()) {
if (esp_cpu_in_ocd_debug_mode()) {
asm("break.n 1");
}
commonErrorHandler(frame);
@ -197,7 +198,7 @@ void xt_unhandled_exception(XtExcFrame *frame)
}
panicPutStr(" occurred on core ");
panicPutDec(xPortGetCoreID());
if (inOCDMode()) {
if (esp_cpu_in_ocd_debug_mode()) {
panicPutStr(" at pc=");
panicPutHex(regs[1]);
panicPutStr(". Setting bp and returning..\r\n");
@ -255,6 +256,7 @@ static inline bool stackPointerIsSane(uint32_t sp)
{
return !(sp < 0x3ffae010 || sp > 0x3ffffff0 || ((sp & 0xf) != 0));
}
static void putEntry(uint32_t pc, uint32_t sp)
{
if (pc & 0x80000000) {
@ -265,7 +267,8 @@ static void putEntry(uint32_t pc, uint32_t sp)
panicPutStr(":0x");
panicPutHex(sp);
}
void doBacktrace(XtExcFrame *frame)
static void doBacktrace(XtExcFrame *frame)
{
uint32_t i = 0, pc = frame->pc, sp = frame->a1;
panicPutStr("\nBacktrace:");
@ -291,7 +294,7 @@ void doBacktrace(XtExcFrame *frame)
We arrive here after a panic or unhandled exception, when no OCD is detected. Dump the registers to the
serial port and either jump to the gdb stub, halt the CPU or reboot.
*/
void commonErrorHandler(XtExcFrame *frame)
static void commonErrorHandler(XtExcFrame *frame)
{
int *regs = (int *)frame;
int x, y;
@ -304,21 +307,28 @@ void commonErrorHandler(XtExcFrame *frame)
//Feed the watchdogs, so they will give us time to print out debug info
reconfigureAllWdts();
panicPutStr("Register dump:\r\n");
/* only dump registers for 'real' crashes, if crashing via abort()
the register window is no longer useful.
*/
if (!abort_called) {
panicPutStr("Register dump:\r\n");
for (x = 0; x < 24; x += 4) {
for (y = 0; y < 4; y++) {
if (sdesc[x + y][0] != 0) {
panicPutStr(sdesc[x + y]);
panicPutStr(": 0x");
panicPutHex(regs[x + y + 1]);
panicPutStr(" ");
for (x = 0; x < 24; x += 4) {
for (y = 0; y < 4; y++) {
if (sdesc[x + y][0] != 0) {
panicPutStr(sdesc[x + y]);
panicPutStr(": 0x");
panicPutHex(regs[x + y + 1]);
panicPutStr(" ");
}
}
panicPutStr("\r\n");
}
panicPutStr("\r\n");
}
/* With windowed ABI backtracing is easy, let's do it. */
doBacktrace(frame);
#if CONFIG_ESP32_PANIC_GDBSTUB
disableAllWdts();
panicPutStr("Entering gdb stub now.\r\n");
@ -339,8 +349,7 @@ void commonErrorHandler(XtExcFrame *frame)
void esp_set_breakpoint_if_jtag(void *fn)
{
if (!inOCDMode()) {
return;
if (esp_cpu_in_ocd_debug_mode()) {
setFirstBreakpoint((uint32_t)fn);
}
setFirstBreakpoint((uint32_t)fn);
}

View File

@ -27,7 +27,7 @@ static const char phy_init_magic_pre[] = PHY_INIT_MAGIC;
* @brief Structure containing default recommended PHY initialization parameters.
*/
static const esp_phy_init_data_t phy_init_data= {
.param_ver_id = 0,
.param_ver_id = 1,
.crystal_select = 3,
.wifi_rx_gain_swp_step_1 = 0x05,
.wifi_rx_gain_swp_step_2 = 0x04,
@ -75,7 +75,7 @@ static const esp_phy_init_data_t phy_init_data= {
.target_power_qdb_1 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 76),
.target_power_qdb_2 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 74),
.target_power_qdb_3 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 68),
.target_power_qdb_4 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 64),
.target_power_qdb_4 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 60),
.target_power_qdb_5 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 52),
.target_power_index_mcs0 = 0,
.target_power_index_mcs1 = 0,

View File

@ -98,7 +98,7 @@ static void timer_test(int flags) {
esp_intr_get_intno(inth[0]), esp_intr_get_intno(inth[1]),
esp_intr_get_intno(inth[2]), esp_intr_get_intno(inth[3]));
printf("Timer values on start: %d %d %d %d\n", count[0], count[1], count[2], count[3]);
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
printf("Timer values after 1 sec: %d %d %d %d\n", count[0], count[1], count[2], count[3]);
TEST_ASSERT(count[0]==0);
TEST_ASSERT(count[1]!=0);
@ -110,7 +110,7 @@ static void timer_test(int flags) {
esp_intr_disable(inth[1]);
esp_intr_disable(inth[2]);
for (x=0; x<4; x++) count[x]=0;
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
printf("Timer values after 1 sec: %d %d %d %d\n", count[0], count[1], count[2], count[3]);
TEST_ASSERT(count[0]!=0);
TEST_ASSERT(count[1]==0);
@ -122,7 +122,7 @@ static void timer_test(int flags) {
esp_intr_disable(inth[0]);
esp_intr_disable(inth[3]);
for (x=0; x<4; x++) count[x]=0;
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
printf("Timer values after 1 sec: %d %d %d %d\n", count[0], count[1], count[2], count[3]);
TEST_ASSERT(count[0]==0);
TEST_ASSERT(count[1]!=0);
@ -152,18 +152,18 @@ void local_timer_test()
printf("Int timer 1 intno %d\n", esp_intr_get_intno(ih));
xthal_set_ccompare(1, xthal_get_ccount()+8000000);
int_timer_ctr=0;
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
printf("Timer val after 1 sec: %d\n", int_timer_ctr);
TEST_ASSERT(int_timer_ctr!=0);
printf("Disabling int\n");
esp_intr_disable(ih);
int_timer_ctr=0;
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
printf("Timer val after 1 sec: %d\n", int_timer_ctr);
TEST_ASSERT(int_timer_ctr==0);
printf("Re-enabling\n");
esp_intr_enable(ih);
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
printf("Timer val after 1 sec: %d\n", int_timer_ctr);
TEST_ASSERT(int_timer_ctr!=0);
@ -173,12 +173,12 @@ void local_timer_test()
r=esp_intr_alloc(ETS_INTERNAL_TIMER1_INTR_SOURCE, ESP_INTR_FLAG_INTRDISABLED, int_timer_handler, NULL, &ih);
TEST_ASSERT(r==ESP_OK);
int_timer_ctr=0;
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
printf("Timer val after 1 sec: %d\n", int_timer_ctr);
TEST_ASSERT(int_timer_ctr==0);
printf("Re-enabling\n");
esp_intr_enable(ih);
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
printf("Timer val after 1 sec: %d\n", int_timer_ctr);
TEST_ASSERT(int_timer_ctr!=0);
r=esp_intr_free(ih);

View File

@ -121,4 +121,101 @@ config ESPTOOLPY_FLASHSIZE
default "8MB" if ESPTOOLPY_FLASHSIZE_8MB
default "16MB" if ESPTOOLPY_FLASHSIZE_16MB
config ESPTOOLPY_FLASHSIZE_DETECT
bool "Detect flash size when flashing bootloader"
default y
help
If this option is set, 'make flash' targets will automatically detect
the flash size and update the bootloader image when flashing.
choice ESPTOOLPY_BEFORE
prompt "Before flashing"
default ESPTOOLPY_BEFORE_RESET
help
Configure whether esptool.py should reset the ESP32 before flashing.
Automatic resetting depends on the RTS & DTR signals being
wired from the serial port to the ESP32. Most USB development
boards do this internally.
The "Reset with ESP32R0 Windows workaround" option works
around an automatic reset bug in hardware, when using Windows
with some development boards. This fix only works if you're
using a silicon revision 0 ESP32.
config ESPTOOLPY_BEFORE_RESET
bool "Reset to bootloader"
config ESPTOOLPY_BEFORE_NORESET
bool "No reset"
config ESPTOOLPY_BEFORE_ESP32R0
bool "Reset with ESP32R0 Windows workaround"
endchoice
config ESPTOOLPY_BEFORE
string
default "default_reset" if ESPTOOLPY_BEFORE_RESET
default "no_reset" if ESPTOOLPY_BEFORE_NORESET
default "esp32r0" if ESPTOOLPY_BEFORE_ESP32R0
choice ESPTOOLPY_AFTER
prompt "After flashing"
default ESPTOOLPY_AFTER_RESET
help
Configure whether esptool.py should reset the ESP32 after flashing.
Automatic resetting depends on the RTS & DTR signals being
wired from the serial port to the ESP32. Most USB development
boards do this internally.
config ESPTOOLPY_AFTER_RESET
bool "Reset after flashing"
config ESPTOOLPY_AFTER_NORESET
bool "Stay in bootloader"
endchoice
config ESPTOOLPY_AFTER
string
default "hard_reset" if ESPTOOLPY_AFTER_RESET
default "no_reset" if ESPTOOLPY_AFTER_NORESET
choice MONITOR_BAUD
prompt "'make monitor' baud rate"
default MONITOR_BAUD_115200B
help
Baud rate to use when running 'make monitor' to view serial output
from a running chip.
Can override by setting the MONITORBAUD environment variable.
config MONITOR_BAUD_9600B
bool "9600 bps"
config MONITOR_BAUD_57600B
bool "57600 bps"
config MONITOR_BAUD_115200B
bool "115200 bps"
config MONITOR_BAUD_230400B
bool "230400 bps"
config MONITOR_BAUD_921600B
bool "921600 bps"
config MONITOR_BAUD_2MB
bool "2 Mbps"
config MONITOR_BAUD_OTHER
bool "Custom baud rate"
endchoice
config MONITOR_BAUD_OTHER_VAL
int "Custom baud rate value" if MONITOR_BAUD_OTHER
default 115200
config MONITOR_BAUD
int
default 9600 if MONITOR_BAUD_9600B
default 57600 if MONITOR_BAUD_57600B
default 115200 if MONITOR_BAUD_115200B
default 230400 if MONITOR_BAUD_230400B
default 921600 if MONITOR_BAUD_921600B
default 2000000 if MONITOR_BAUD_2MB
default MONITOR_BAUD_OTHER_VAL if MONITOR_BAUD_OTHER
endmenu

View File

@ -13,7 +13,7 @@ PYTHON ?= $(call dequote,$(CONFIG_PYTHON))
#
ESPTOOLPY_SRC := $(COMPONENT_PATH)/esptool/esptool.py
ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32
ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD)
ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD) --before $(CONFIG_ESPTOOLPY_BEFORE) --after $(CONFIG_ESPTOOLPY_AFTER)
# Supporting esptool command line tools
ESPEFUSEPY := $(PYTHON) $(COMPONENT_PATH)/esptool/espefuse.py
@ -21,19 +21,24 @@ ESPSECUREPY := $(PYTHON) $(COMPONENT_PATH)/esptool/espsecure.py
export ESPSECUREPY # is used in bootloader_support component
ESPTOOL_FLASH_OPTIONS := --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) --flash_size $(ESPFLASHSIZE)
ifdef CONFIG_ESPTOOLPY_FLASHSIZE_DETECT
ESPTOOL_WRITE_FLASH_OPTIONS := --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) --flash_size detect
else
ESPTOOL_WRITE_FLASH_OPTIONS := $(ESPTOOL_FLASH_OPTIONS)
endif
ESPTOOL_ELF2IMAGE_OPTIONS :=
ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) $(ESPTOOL_FLASH_OPTIONS)
ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) $(ESPTOOL_WRITE_FLASH_OPTIONS)
ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN)
ifdef CONFIG_SECURE_BOOT_ENABLED
ifdef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
ifndef IS_BOOTLOADER_BUILD
# for secure boot, add a signing step to get from unsiged app to signed app
# for locally signed secure boot image, add a signing step to get from unsigned app to signed app
APP_BIN_UNSIGNED := $(APP_BIN:.bin=-unsigned.bin)
$(APP_BIN): $(APP_BIN_UNSIGNED) $(SECURE_BOOT_SIGNING_KEY)
$(APP_BIN): $(APP_BIN_UNSIGNED) $(SECURE_BOOT_SIGNING_KEY) $(SDKCONFIG_MAKEFILE)
$(ESPSECUREPY) sign_data --keyfile $(SECURE_BOOT_SIGNING_KEY) -o $@ $<
endif
endif
@ -43,17 +48,31 @@ APP_BIN_UNSIGNED ?= $(APP_BIN)
$(APP_BIN_UNSIGNED): $(APP_ELF) $(ESPTOOLPY_SRC)
$(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) $(ESPTOOL_ELF2IMAGE_OPTIONS) -o $@ $<
flash: all_binaries $(ESPTOOLPY_SRC)
flash: all_binaries $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash)
@echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(CONFIG_APP_OFFSET))..."
ifdef CONFIG_SECURE_BOOT_ENABLED
@echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)"
endif
$(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS)
app-flash: $(APP_BIN) $(ESPTOOLPY_SRC)
app-flash: $(APP_BIN) $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash)
@echo "Flashing app to serial port $(ESPPORT), offset $(CONFIG_APP_OFFSET)..."
$(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN)
# Submodules normally added in component.mk, but can be added
# at the project level as long as qualified path
COMPONENT_SUBMODULES += $(COMPONENT_PATH)/esptool
erase_flash:
@echo "Erasing entire flash..."
$(ESPTOOLPY_SERIAL) erase_flash
MONITORBAUD ?= $(CONFIG_MONITOR_BAUD)
# note: if you want to run miniterm from command line, can simply run
# miniterm.py on the console. The '$(PYTHON) -m serial.tools.miniterm'
# is to allow for the $(PYTHON) variable overriding the python path.
monitor: $(call prereq_if_explicit,%flash)
$(PYTHON) -m serial.tools.miniterm --rts 0 --dtr 0 --raw $(ESPPORT) $(MONITORBAUD)
.PHONY: erase_flash

@ -1 +1 @@
Subproject commit adc914b91ac6d2cfd1ace56307b4374eb9439e14
Subproject commit fe69994270e2a450aad3e94a409b58460b1a214f

View File

@ -3,18 +3,32 @@ menuconfig ETHERNET
default n
help
Enable this option to enable ethernet driver and show the menu with ethernet features.
config DMA_RX_BUF_NUM
int "Dma Rx Buf Num"
int "DMA Rx Buf Num"
default 10
depends on ETHERNET
help
Dma rx buf num ,can not be 0 .
config DMA_TX_BUF_NUM
int "Dma Tx Buf Num"
int "DMA Tx Buf Num"
default 10
depends on ETHERNET
help
Dma tx Buf num ,can not be 0.
config EMAC_L2_TO_L3_RX_BUF_MODE
bool "L2 To L3 RX BUF COPY MODE"
default n
depends on ETHERNET
help
Receive Buf user copy mode or pointer mode.
config EMAC_TASK_PRIORITY
int "EMAC_TASK_PRIORITY"
default 20
depends on ETHERNET
help
Emac task priority ,suggest 3 ~ 23.

View File

@ -19,6 +19,7 @@
#include "esp_err.h"
#include "emac_dev.h"
#include "esp_eth.h"
#ifdef __cplusplus
extern "C" {
@ -32,11 +33,6 @@ typedef struct {
emac_par_t par;
} emac_event_t;
enum emac_mode {
EMAC_MODE_RMII = 0,
EMAC_MDOE_MII,
};
enum emac_runtime_status {
EMAC_RUNTIME_NOT_INIT = 0,
EMAC_RUNTIME_INIT,
@ -45,36 +41,37 @@ enum emac_runtime_status {
};
enum {
SIG_EMAC_RX_UNAVAIL,
SIG_EMAC_TX_DONE,
SIG_EMAC_RX_DONE,
SIG_EMAC_TX,
SIG_EMAC_START,
SIG_EMAC_STOP,
SIG_EMAC_CHECK_LINK,
SIG_EMAC_MAX
};
typedef void (*emac_phy_fun)(void);
typedef esp_err_t (*emac_tcpip_input_fun)(void *buffer, uint16_t len, void *eb);
typedef void (*emac_gpio_config_func)(void);
struct emac_config_data {
unsigned int phy_addr;
enum emac_mode mac_mode;
eth_phy_base_t phy_addr;
eth_mode_t mac_mode;
struct dma_extended_desc *dma_etx;
unsigned int cur_tx;
unsigned int dirty_tx;
signed int cnt_tx;
uint32_t cur_tx;
uint32_t dirty_tx;
int32_t cnt_tx;
struct dma_extended_desc *dma_erx;
unsigned int cur_rx;
unsigned int dirty_rx;
signed int cnt_rx;
unsigned int rx_need_poll;
uint32_t cur_rx;
uint32_t dirty_rx;
int32_t cnt_rx;
uint32_t rx_need_poll;
bool phy_link_up;
enum emac_runtime_status emac_status;
uint8_t macaddr[6];
emac_phy_fun phy_init;
emac_tcpip_input_fun emac_tcpip_input;
emac_gpio_config_func emac_gpio_config;
eth_phy_func phy_init;
eth_tcpip_input_func emac_tcpip_input;
eth_gpio_config_func emac_gpio_config;
eth_phy_check_link_func emac_phy_check_link;
eth_phy_check_init_func emac_phy_check_init;
eth_phy_get_speed_mode_func emac_phy_get_speed_mode;
eth_phy_get_duplex_mode_func emac_phy_get_duplex_mode;
};
enum emac_post_type {
@ -103,18 +100,15 @@ struct emac_close_cmd {
#if CONFIG_ETHERNET
#define DMA_RX_BUF_NUM CONFIG_DMA_RX_BUF_NUM
#define DMA_TX_BUF_NUM CONFIG_DMA_TX_BUF_NUM
#define EMAC_TASK_PRIORITY CONFIG_EMAC_TASK_PRIORITY
#else
#define DMA_RX_BUF_NUM 1
#define DMA_TX_BUF_NUM 1
#define EMAC_TASK_PRIORITY 10
#endif
#define DMA_RX_BUF_SIZE 1600
#define DMA_TX_BUF_SIZE 1600
//lwip err
#define ERR_OK 0
#define ERR_MEM -1
#define ERR_IF -16
#define EMAC_CMD_OK 0
#define EMAC_CMD_FAIL -1

View File

@ -34,18 +34,6 @@
static const char *TAG = "emac";
void emac_poll_tx_cmd(void)
{
//write any to wake up dma
REG_WRITE(EMAC_DMATXPOLLDEMAND_REG, 1);
}
void emac_poll_rx_cmd(void)
{
//write any to wake up dma
REG_WRITE(EMAC_DMARXPOLLDEMAND_REG, 1);
}
void emac_enable_dma_tx(void)
{
REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_START_STOP_TRANSMISSION_COMMAND);
@ -66,15 +54,6 @@ void emac_disable_dma_rx(void)
REG_CLR_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_START_STOP_RECEIVE);
}
uint32_t emac_read_tx_cur_reg(void)
{
return REG_READ(EMAC_DMATXCURRDESC_REG);
}
uint32_t emac_read_rx_cur_reg(void)
{
return REG_READ(EMAC_DMARXCURRDESC_REG);
}
uint32_t emac_read_mac_version(void)
{
@ -121,16 +100,18 @@ void emac_dma_init(void)
REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_FORWARD_UNDERSIZED_GOOD_FRAMES);
REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_OPERATE_SECOND_FRAME);
REG_SET_FIELD(EMAC_DMABUSMODE_REG, EMAC_PROG_BURST_LEN, 4);
REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG,EMAC_DMAOPERATION_MODE_REG);
}
void emac_mac_init(void)
{
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACRX);
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACTX);
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACDUPLEX);
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACMIIGMII);
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACFESPEED);
REG_SET_BIT(EMAC_GMACFRAMEFILTER_REG, EMAC_PROMISCUOUS_MODE);
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACRX);
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACTX);
}
void emac_set_clk_rmii(void)

View File

@ -49,14 +49,52 @@ uint32_t emac_read_mac_version(void);
void emac_dma_init(void);
void emac_mac_init(void);
void emac_enable_dma_tx(void);
void emac_poll_tx_cmd(void);
uint32_t emac_read_tx_cur_reg(void);
void emac_enable_dma_rx(void);
uint32_t emac_read_rx_cur_reg(void);
void emac_poll_rx_cmd(void);
void emac_disable_dma_tx(void);
void emac_disable_dma_rx(void);
uint32_t inline emac_read_tx_cur_reg(void)
{
return REG_READ(EMAC_DMATXCURRDESC_REG);
}
uint32_t inline emac_read_rx_cur_reg(void)
{
return REG_READ(EMAC_DMARXCURRDESC_REG);
}
void inline emac_poll_tx_cmd(void)
{
//write any to wake up dma
REG_WRITE(EMAC_DMATXPOLLDEMAND_REG, 1);
}
void inline emac_poll_rx_cmd(void)
{
//write any to wake up dma
REG_WRITE(EMAC_DMARXPOLLDEMAND_REG, 1);
}
void inline emac_disable_rx_intr(void)
{
REG_CLR_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_INTERRUPT_ENABLE);
}
void inline emac_enable_rx_intr(void)
{
REG_SET_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_INTERRUPT_ENABLE);
}
void inline emac_disable_rx_unavail_intr(void)
{
REG_CLR_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_BUFFER_UNAVAILABLE_ENABLE);
}
void inline emac_enable_rx_unavail_intr(void)
{
REG_SET_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_BUFFER_UNAVAILABLE_ENABLE);
}
#ifdef __cplusplus
}
#endif

View File

@ -47,6 +47,8 @@
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include "lwip/err.h"
#define EMAC_EVT_QNUM 200
#define EMAC_SIG_MAX 50
@ -63,7 +65,8 @@ static xTaskHandle emac_task_hdl;
static xQueueHandle emac_xqueue;
static uint8_t emac_sig_cnt[EMAC_SIG_MAX] = {0};
static TimerHandle_t emac_timer = NULL;
static SemaphoreHandle_t emac_rx_xMutex = NULL;
static SemaphoreHandle_t emac_tx_xMutex = NULL;
static const char *TAG = "emac";
static esp_err_t emac_ioctl(emac_sig_t sig, emac_par_t par);
@ -82,20 +85,24 @@ void esp_eth_get_mac(uint8_t mac[6])
static void emac_setup_tx_desc(struct dma_extended_desc *tx_desc , uint32_t size)
{
tx_desc->basic.desc0 = EMAC_DESC_TX_OWN | EMAC_DESC_INT_COMPL | EMAC_DESC_LAST_SEGMENT | EMAC_DESC_FIRST_SEGMENT | EMAC_DESC_SECOND_ADDR_CHAIN;
tx_desc->basic.desc1 = size & 0xfff;
tx_desc->basic.desc0 = EMAC_DESC_INT_COMPL | EMAC_DESC_LAST_SEGMENT | EMAC_DESC_FIRST_SEGMENT | EMAC_DESC_SECOND_ADDR_CHAIN;
tx_desc->basic.desc0 = EMAC_DESC_TX_OWN | EMAC_DESC_INT_COMPL | EMAC_DESC_LAST_SEGMENT | EMAC_DESC_FIRST_SEGMENT | EMAC_DESC_SECOND_ADDR_CHAIN;
}
static void emac_clean_tx_desc(struct dma_extended_desc *tx_desc)
{
tx_desc->basic.desc0 = 0;
tx_desc->basic.desc1 = 0;
tx_desc->basic.desc0 = 0;
}
static void emac_clean_rx_desc(struct dma_extended_desc *rx_desc)
static void emac_clean_rx_desc(struct dma_extended_desc *rx_desc ,uint32_t buf_ptr)
{
rx_desc->basic.desc0 = EMAC_DESC_RX_OWN;
if(buf_ptr != 0) {
rx_desc->basic.desc2 = buf_ptr;
}
rx_desc->basic.desc1 = EMAC_DESC_RX_SECOND_ADDR_CHAIN | DMA_RX_BUF_SIZE;
rx_desc->basic.desc0 = EMAC_DESC_RX_OWN;
}
static void emac_set_tx_base_reg(void)
@ -156,18 +163,15 @@ static void emac_init_dma_chain(void)
dma_phy = (uint32_t)(emac_config.dma_erx);
p = emac_config.dma_erx;
for (i = 0; i < (DMA_TX_BUF_NUM - 1); i++ ) {
for (i = 0; i < (DMA_RX_BUF_NUM - 1); i++ ) {
dma_phy += sizeof(struct dma_extended_desc);
emac_clean_rx_desc(p);
emac_clean_rx_desc(p, (uint32_t)(&emac_dma_rx_buf[0]) + (i * DMA_RX_BUF_SIZE));
p->basic.desc3 = dma_phy;
p->basic.desc2 = (uint32_t)(&emac_dma_rx_buf[0]) + (i * DMA_RX_BUF_SIZE);
p++;
}
p->basic.desc3 = (uint32_t)(emac_config.dma_erx);
p->basic.desc2 = (uint32_t)(&emac_dma_rx_buf[0]) + (i * DMA_RX_BUF_SIZE);
//init desc0 desc1
emac_clean_rx_desc(p);
emac_clean_rx_desc(p, (uint32_t)(&emac_dma_rx_buf[0]) + (i * DMA_RX_BUF_SIZE));
p->basic.desc3 = (uint32_t)(emac_config.dma_erx);
}
void esp_eth_smi_write(uint32_t reg_num, uint16_t value)
@ -207,18 +211,32 @@ static void emac_set_user_config_data(eth_config_t *config )
emac_config.phy_init = config->phy_init;
emac_config.emac_tcpip_input = config->tcpip_input;
emac_config.emac_gpio_config = config->gpio_config;
emac_config.emac_phy_check_link = config->phy_check_link;
emac_config.emac_phy_check_init = config->phy_check_init;
emac_config.emac_phy_get_speed_mode = config->phy_get_speed_mode;
emac_config.emac_phy_get_duplex_mode = config->phy_get_duplex_mode;
}
static void emac_enable_intr()
{
REG_WRITE(EMAC_DMAINTERRUPT_EN_REG, EMAC_INTR_ENABLE_BIT);
}
static void emac_disable_intr()
{
REG_WRITE(EMAC_DMAINTERRUPT_EN_REG, 0);
}
static esp_err_t emac_verify_args(void)
{
esp_err_t ret = ESP_OK;
if (emac_config.phy_addr > 31) {
if (emac_config.phy_addr > PHY31) {
ESP_LOGE(TAG, "phy addr err");
ret = ESP_FAIL;
}
if (emac_config.mac_mode != EMAC_MODE_RMII) {
if (emac_config.mac_mode != ETH_MODE_RMII) {
ESP_LOGE(TAG, "mac mode err,now only support RMII");
ret = ESP_FAIL;
}
@ -238,6 +256,26 @@ static esp_err_t emac_verify_args(void)
ret = ESP_FAIL;
}
if (emac_config.emac_phy_check_link == NULL) {
ESP_LOGE(TAG, "phy check link func is null");
ret = ESP_FAIL;
}
if (emac_config.emac_phy_check_init == NULL) {
ESP_LOGE(TAG, "phy check init func is null");
ret = ESP_FAIL;
}
if (emac_config.emac_phy_get_speed_mode == NULL) {
ESP_LOGE(TAG, "phy get speed mode func is null");
ret = ESP_FAIL;
}
if (emac_config.emac_phy_get_duplex_mode == NULL) {
ESP_LOGE(TAG, "phy get duplex mode func is null");
ret = ESP_FAIL;
}
return ret;
}
@ -255,7 +293,13 @@ static void emac_process_tx(void)
{
uint32_t cur_tx_desc = emac_read_tx_cur_reg();
while (((uint32_t) & (emac_config.dma_etx[emac_config.dirty_tx].basic.desc0) != cur_tx_desc)) {
if(emac_config.emac_status == EMAC_RUNTIME_STOP) {
return;
}
xSemaphoreTakeRecursive( emac_tx_xMutex, ( TickType_t ) portMAX_DELAY );
while (((uint32_t) &(emac_config.dma_etx[emac_config.dirty_tx].basic.desc0) != cur_tx_desc)) {
emac_clean_tx_desc(&(emac_config.dma_etx[emac_config.dirty_tx]));
emac_config.dirty_tx = (emac_config.dirty_tx + 1) % DMA_TX_BUF_NUM;
emac_config.cnt_tx --;
@ -263,11 +307,33 @@ static void emac_process_tx(void)
if (emac_config.cnt_tx < 0) {
ESP_LOGE(TAG, "emac tx chain err");
}
cur_tx_desc = emac_read_tx_cur_reg();
}
xSemaphoreGiveRecursive( emac_tx_xMutex );
}
void esp_eth_free_rx_buf(void *buf)
{
xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY );
emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.cur_rx]),(uint32_t) buf);
emac_config.cur_rx = (emac_config.cur_rx + 1) % DMA_RX_BUF_NUM;
emac_config.cnt_rx--;
if(emac_config.cnt_rx < 0) {
ESP_LOGE(TAG, "emac rx buf err!!\n");
}
emac_poll_rx_cmd();
xSemaphoreGiveRecursive( emac_rx_xMutex );
}
#if CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE
static void emac_process_rx(void)
{
if(emac_config.emac_status == EMAC_RUNTIME_STOP) {
return;
}
uint32_t cur_rx_desc = emac_read_rx_cur_reg();
while (((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc)) {
@ -275,17 +341,116 @@ static void emac_process_rx(void)
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
(((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]));
emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]),(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2));
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
if (emac_config.rx_need_poll != 0) {
emac_poll_rx_cmd();
emac_config.rx_need_poll = 0;
}
//if open this ,one intr can do many intrs ?
//cur_rx_desc = emac_read_rx_cur_reg();
cur_rx_desc = emac_read_rx_cur_reg();
}
emac_enable_rx_intr();
}
static void emac_process_rx_unavail(void)
{
if(emac_config.emac_status == EMAC_RUNTIME_STOP) {
return;
}
uint32_t dirty_cnt = 0;
while (dirty_cnt < DMA_RX_BUF_NUM) {
if(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 == EMAC_DESC_RX_OWN) {
break;
}
dirty_cnt ++;
//copy data to lwip
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
(((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]),(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2));
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
}
emac_enable_rx_intr();
emac_enable_rx_unavail_intr();
emac_poll_rx_cmd();
}
#else
static void emac_process_rx_unavail(void)
{
if(emac_config.emac_status == EMAC_RUNTIME_STOP) {
return;
}
xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY );
while (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
//copy data to lwip
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
(((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
emac_config.cnt_rx++;
if(emac_config.cnt_rx > DMA_RX_BUF_NUM) {
ESP_LOGE(TAG, "emac rx unavail buf err !!\n");
}
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
}
emac_enable_rx_intr();
emac_enable_rx_unavail_intr();
xSemaphoreGiveRecursive( emac_rx_xMutex );
}
static void emac_process_rx(void)
{
if(emac_config.emac_status == EMAC_RUNTIME_STOP) {
return;
}
uint32_t cur_rx_desc = emac_read_rx_cur_reg();
xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY );
if(((uint32_t) &(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc)) {
while (((uint32_t) &(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc) && emac_config.cnt_rx < DMA_RX_BUF_NUM ) {
//copy data to lwip
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
(((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
emac_config.cnt_rx++;
if(emac_config.cnt_rx > DMA_RX_BUF_NUM ) {
ESP_LOGE(TAG, "emac rx buf err!!\n");
}
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
cur_rx_desc = emac_read_rx_cur_reg();
}
} else {
if(emac_config.cnt_rx < DMA_RX_BUF_NUM) {
if((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) == 0) {
while (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
//copy data to lwip
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
(((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
emac_config.cnt_rx++;
if(emac_config.cnt_rx > DMA_RX_BUF_NUM) {
ESP_LOGE(TAG,"emac rx buf err!!!\n");
}
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
}
}
}
}
emac_enable_rx_intr();
xSemaphoreGiveRecursive( emac_rx_xMutex );
}
#endif
//TODO other events need to do something
static void IRAM_ATTR emac_process_intr(void *arg)
{
@ -295,35 +460,37 @@ static void IRAM_ATTR emac_process_intr(void *arg)
//clr intrs
REG_WRITE(EMAC_DMASTATUS_REG, event);
if (event & EMAC_RECV_BUF_UNAVAIL) {
emac_config.rx_need_poll = 1;
} else if (event & EMAC_TRANS_INT) {
emac_post(SIG_EMAC_TX_DONE, 0);
} else if (event & EMAC_RECV_INT) {
if (event & EMAC_RECV_INT) {
emac_disable_rx_intr();
emac_post(SIG_EMAC_RX_DONE, 0);
} else {
//other events
}
if (event & EMAC_RECV_BUF_UNAVAIL) {
emac_disable_rx_unavail_intr();
emac_post(SIG_EMAC_RX_UNAVAIL,0);
}
if (event & EMAC_TRANS_INT) {
emac_post(SIG_EMAC_TX_DONE, 0);
}
}
//ToDo: this should only be called once because this allocates the interrupt as well.
static void emac_enable_intr()
static void emac_check_phy_init(void)
{
//init emac intr
esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, emac_process_intr, NULL, NULL);
REG_WRITE(EMAC_DMAINTERRUPT_EN_REG, EMAC_INTR_ENABLE_BIT);
}
emac_config.emac_phy_check_init();
if(emac_config.emac_phy_get_duplex_mode() == ETH_MDOE_FULLDUPLEX) {
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACDUPLEX);
} else {
REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACDUPLEX);
}
if(emac_config.emac_phy_get_speed_mode() == ETH_SPEED_MODE_100M) {
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACFESPEED);
} else {
REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACFESPEED);
}
static void emac_disable_intr()
{
REG_WRITE(EMAC_DMAINTERRUPT_EN_REG, 0);
emac_mac_init();
}
static bool emac_check_phy_link_status(void)
{
return ((esp_eth_smi_read(1) & 0x4) == 0x4 );
}
static void emac_process_link_updown(bool link_status)
{
system_event_t evt;
@ -331,10 +498,10 @@ static void emac_process_link_updown(bool link_status)
emac_config.phy_link_up = link_status;
if (link_status == true) {
emac_check_phy_init();
ESP_LOGI(TAG, "eth link_up!!!");
emac_enable_dma_tx();
emac_enable_dma_rx();
ets_delay_us(200000);
evt.event_id = SYSTEM_EVENT_ETH_CONNECTED;
} else {
ESP_LOGI(TAG, "eth link_down!!!");
@ -356,26 +523,20 @@ static void emac_hw_init(void)
//ipc TODO
}
static esp_err_t emac_xmit(void *param)
esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size)
{
struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)param;
struct emac_tx_cmd *cmd = (struct emac_tx_cmd *)(post_cmd->cmd);
esp_err_t ret = ESP_OK;
void *buf = cmd->buf;
uint16_t size = cmd->size;
if (emac_config.emac_status != EMAC_RUNTIME_START || emac_config.emac_status == EMAC_RUNTIME_NOT_INIT) {
ESP_LOGI(TAG, "tx netif close");
cmd->err = ERR_IF;
ret = ESP_FAIL;
ret = ERR_IF;
goto _exit;
}
if (emac_config.cnt_tx == DMA_TX_BUF_NUM) {
ESP_LOGI(TAG, "tx buf full");
cmd->err = ERR_MEM;
ret = ESP_FAIL;
xSemaphoreTakeRecursive( emac_tx_xMutex, ( TickType_t ) portMAX_DELAY );
if (emac_config.cnt_tx == DMA_TX_BUF_NUM -1) {
ESP_LOGD(TAG, "tx buf full");
ret = ERR_MEM;
goto _exit;
}
@ -390,26 +551,23 @@ static esp_err_t emac_xmit(void *param)
_exit:
if (post_cmd->post_type == EMAC_POST_SYNC) {
xSemaphoreGive(emac_g_sem);
}
xSemaphoreGiveRecursive( emac_tx_xMutex );
return ret;
}
static void emac_init_default_data(void)
{
emac_config.rx_need_poll = 0;
memset((uint8_t *)&emac_config, 0,sizeof(struct emac_config_data));
}
void emac_link_check_func(void *pv_parameters)
void emac_process_link_check(void)
{
if (emac_config.emac_status != EMAC_RUNTIME_START ||
emac_config.emac_status == EMAC_RUNTIME_NOT_INIT) {
return;
}
if (emac_check_phy_link_status() == true ) {
if (emac_config.emac_phy_check_link() == true ) {
if (emac_config.phy_link_up == false) {
emac_process_link_updown(true);
}
@ -420,9 +578,14 @@ void emac_link_check_func(void *pv_parameters)
}
}
void emac_link_check_func(void *pv_parameters)
{
emac_post(SIG_EMAC_CHECK_LINK,0);
}
static bool emac_link_check_timer_init(void)
{
emac_timer = xTimerCreate("emac_timer", (1000 / portTICK_RATE_MS),
emac_timer = xTimerCreate("emac_timer", (2000 / portTICK_PERIOD_MS),
pdTRUE, (void *)rand(), emac_link_check_func);
if (emac_timer == NULL) {
return false;
@ -473,18 +636,11 @@ static void emac_start(void *param)
emac_set_tx_base_reg();
emac_set_rx_base_reg();
emac_mac_init();
emac_config.phy_init();
//for test
//emac_wait_linkup();
//mmc not support
//ptp TODO
//enable emac intr
emac_enable_intr();
emac_config.emac_status = EMAC_RUNTIME_START;
@ -573,7 +729,7 @@ esp_err_t esp_eth_disable(void)
return close_cmd.err;
}
if (emac_config.emac_status != EMAC_RUNTIME_NOT_INIT) {
if (emac_config.emac_status == EMAC_RUNTIME_START) {
if (emac_ioctl(SIG_EMAC_STOP, (emac_par_t)(&post_cmd)) != 0) {
close_cmd.err = EMAC_CMD_FAIL;
}
@ -608,9 +764,6 @@ static esp_err_t emac_ioctl(emac_sig_t sig, emac_par_t par)
case SIG_EMAC_TX_DONE:
emac_process_tx();
break;
case SIG_EMAC_TX:
emac_xmit((void *)par);
break;
case SIG_EMAC_START:
emac_start((void *)par);
break;
@ -626,29 +779,6 @@ static esp_err_t emac_ioctl(emac_sig_t sig, emac_par_t par)
return ret;
}
esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size)
{
struct emac_post_cmd post_cmd;
struct emac_tx_cmd tx_cmd;
post_cmd.cmd = (void *)(&tx_cmd);
if (emac_check_phy_link_status() == false) {
emac_process_link_updown(false);
tx_cmd.err = ERR_IF;
} else {
tx_cmd.buf = buf;
tx_cmd.size = size;
tx_cmd.err = ERR_OK;
if (emac_ioctl(SIG_EMAC_TX, (emac_par_t)(&post_cmd)) != 0) {
tx_cmd.err = ERR_MEM;
}
}
return tx_cmd.err;
}
void emac_task(void *pv)
{
emac_event_t e;
@ -662,18 +792,21 @@ void emac_task(void *pv)
case SIG_EMAC_RX_DONE:
emac_process_rx();
break;
case SIG_EMAC_RX_UNAVAIL:
emac_process_rx_unavail();
break;
case SIG_EMAC_TX_DONE:
emac_process_tx();
break;
case SIG_EMAC_TX:
emac_xmit((void *)e.par);
break;
case SIG_EMAC_START:
emac_start((void *)e.par);
break;
case SIG_EMAC_STOP:
emac_stop((void *)e.par);
break;
case SIG_EMAC_CHECK_LINK:
emac_process_link_check();
break;
default:
ESP_LOGE(TAG, "unexpect sig %d", e.sig);
break;
@ -684,27 +817,35 @@ void emac_task(void *pv)
esp_err_t IRAM_ATTR emac_post(emac_sig_t sig, emac_par_t par)
{
portENTER_CRITICAL(&g_emac_mux);
if(sig <= SIG_EMAC_RX_DONE) {
if (emac_sig_cnt[sig]) {
return ESP_OK;
} else {
emac_sig_cnt[sig]++;
emac_event_t evt;
signed portBASE_TYPE ret;
evt.sig = sig;
evt.par = par;
portBASE_TYPE tmp;
if (emac_sig_cnt[sig] && sig != SIG_EMAC_TX) {
portEXIT_CRITICAL(&g_emac_mux);
return ESP_OK;
ret = xQueueSendFromISR(emac_xqueue, &evt, &tmp);
if(tmp != pdFALSE) {
portYIELD_FROM_ISR();
}
if(ret != pdPASS) {
return ESP_FAIL;
}
}
} else {
emac_sig_cnt[sig]++;
portEXIT_CRITICAL(&g_emac_mux);
emac_event_t evt;
evt.sig = sig;
evt.par = par;
if (sig <= SIG_EMAC_RX_DONE) {
portBASE_TYPE tmp;
if (xQueueSendFromISR(emac_xqueue, &evt, &tmp) != pdPASS) {
return ESP_FAIL;
}
} else {
if (xQueueSend(emac_xqueue, &evt, 10 / portTICK_RATE_MS) != pdTRUE) {
return ESP_FAIL;
}
if (xQueueSend(emac_xqueue, &evt, 10 / portTICK_PERIOD_MS) != pdTRUE) {
return ESP_FAIL;
}
}
@ -737,7 +878,7 @@ esp_err_t esp_eth_init(eth_config_t *config)
REG_SET_FIELD(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_PHY_INTF_SEL, EMAC_EX_PHY_INTF_RMII);
emac_dma_init();
if (emac_config.mac_mode == EMAC_MODE_RMII) {
if (emac_config.mac_mode == ETH_MODE_RMII) {
emac_set_clk_rmii();
} else {
emac_set_clk_mii();
@ -752,8 +893,12 @@ esp_err_t esp_eth_init(eth_config_t *config)
//init task for emac
emac_g_sem = xSemaphoreCreateBinary();
emac_rx_xMutex = xSemaphoreCreateRecursiveMutex();
emac_tx_xMutex = xSemaphoreCreateRecursiveMutex();
emac_xqueue = xQueueCreate(EMAC_EVT_QNUM, sizeof(emac_event_t));
xTaskCreate(emac_task, "emacT", 2048 * 4, NULL, (19), &emac_task_hdl);
xTaskCreate(emac_task, "emacT", 2048, NULL, EMAC_TASK_PRIORITY, &emac_task_hdl);
esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, emac_process_intr, NULL, NULL);
emac_reset();
emac_enable_clk(false);

View File

@ -22,15 +22,21 @@
extern "C" {
#endif
typedef void (*eth_phy_fun)(void);
typedef esp_err_t (*eth_tcpip_input_fun)(void *buffer, uint16_t len, void *eb);
typedef void (*eth_gpio_config_func)(void);
typedef enum {
ETH_MODE_RMII = 0,
ETH_MDOE_MII,
} eth_mode_t;
typedef enum {
ETH_SPEED_MODE_10M = 0,
ETH_SPEED_MODE_100M,
} eth_speed_mode_t;
typedef enum {
ETH_MODE_HALFDUPLEX = 0,
ETH_MDOE_FULLDUPLEX,
} eth_duplex_mode_t;
typedef enum {
PHY0 = 0,
PHY1,
@ -66,6 +72,15 @@ typedef enum {
PHY31,
} eth_phy_base_t;
typedef bool (*eth_phy_check_link_func)(void);
typedef void (*eth_phy_check_init_func)(void);
typedef eth_speed_mode_t (*eth_phy_get_speed_mode_func)(void);
typedef eth_duplex_mode_t (*eth_phy_get_duplex_mode_func)(void);
typedef void (*eth_phy_func)(void);
typedef esp_err_t (*eth_tcpip_input_func)(void *buffer, uint16_t len, void *eb);
typedef void (*eth_gpio_config_func)(void);
/**
* @brief ethernet configuration
*
@ -73,8 +88,12 @@ typedef enum {
typedef struct {
eth_phy_base_t phy_addr; /*!< phy base addr (0~31) */
eth_mode_t mac_mode; /*!< mac mode only support RMII now */
eth_tcpip_input_fun tcpip_input; /*!< tcpip input func */
eth_phy_fun phy_init; /*!< phy init func */
eth_tcpip_input_func tcpip_input; /*!< tcpip input func */
eth_phy_func phy_init; /*!< phy init func */
eth_phy_check_link_func phy_check_link; /*!< phy check link func */
eth_phy_check_init_func phy_check_init; /*!< phy check init func */
eth_phy_get_speed_mode_func phy_get_speed_mode; /*!< phy check init func */
eth_phy_get_duplex_mode_func phy_get_duplex_mode; /*!< phy check init func */
eth_gpio_config_func gpio_config; /*!< gpio config func */
} eth_config_t;
@ -159,6 +178,16 @@ void esp_eth_smi_write(uint32_t reg_num, uint16_t value);
*/
uint16_t esp_eth_smi_read(uint32_t reg_num);
/**
* @brief Free emac rx buf.
*
* @note buf can not be null,and it is tcpip input buf.
*
* @param[in] buf: start address of recevie packet data.
*
*/
void esp_eth_free_rx_buf(void *buf);
#ifdef __cplusplus
}
#endif

View File

@ -3,7 +3,7 @@ menu "FreeRTOS"
# This is actually also handled in the ESP32 startup code, not only in FreeRTOS.
config FREERTOS_UNICORE
bool "Run FreeRTOS only on first core"
default y
default n
help
This version of FreeRTOS normally takes control of all cores of
the CPU. Select this if you only want to start it on the first core.
@ -54,7 +54,7 @@ config FREERTOS_ASSERT_ON_UNTESTED_FUNCTION
choice FREERTOS_CHECK_STACKOVERFLOW
prompt "Check for stack overflow"
default FREERTOS_CHECK_STACKOVERFLOW_QUICK
default FREERTOS_CHECK_STACKOVERFLOW_CANARY
help
FreeRTOS can check for stack overflows in threads and trigger an user function
called vApplicationStackOverflowHook when this happens.
@ -195,8 +195,6 @@ config FREERTOS_PORTMUX_DEBUG_RECURSIVE
If enabled, additional debug information will be printed for recursive
portMUX usage.
endif # FREERTOS_DEBUG_INTERNALS
endmenu

View File

@ -174,7 +174,7 @@ static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert );
/*-----------------------------------------------------------*/
/* The size of the structure placed at the beginning of each allocated memory
block must by correctly byte aligned. */
block must be correctly byte aligned. */
static const uint32_t uxHeapStructSize = ( ( sizeof ( BlockLink_t ) + BLOCK_HEAD_LEN + BLOCK_TAIL_LEN + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK );
/* Create a couple of list links to mark the start and end of the list. */
@ -583,7 +583,7 @@ const HeapRegionTagged_t *pxHeapRegion;
#if (configENABLE_MEMORY_DEBUG == 1)
{
mem_debug_init(uxHeapStructSize, &xStart, pxEnd, &xMallocMutex, xBlockAllocatedBit);
mem_debug_init(uxHeapStructSize, &xStart, pxEnd, &xMallocMutex);
mem_check_all(0);
}
#endif

View File

@ -22,9 +22,10 @@ typedef struct {
/* Please keep this definition same as BlockLink_t */
typedef struct _os_block_t {
struct _os_block_t *next;
size_t size;
unsigned int xtag;
struct _os_block_t *next; /*<< The next free block in the list. */
int size: 24; /*<< The size of the free block. */
int xtag: 7; /*<< Tag of this region */
int xAllocated: 1; /*<< 1 if allocated */
}os_block_t;
typedef struct {
@ -50,7 +51,7 @@ typedef struct _mem_dbg_ctl{
#define OS_BLOCK(_b) ((os_block_t*)((debug_block_t*)((char*)(_b) + BLOCK_HEAD_LEN)))
#define DEBUG_BLOCK(_b) ((debug_block_t*)((char*)(_b) - BLOCK_HEAD_LEN))
#define HEAD_DOG(_b) ((_b)->head.dog)
#define TAIL_DOG(_b) (*(unsigned int*)((char*)(_b) + (((_b)->os_block.size & (~g_alloc_bit) ) - BLOCK_TAIL_LEN)))
#define TAIL_DOG(_b) (*(unsigned int*)((char*)(_b) + (((_b)->os_block.size ) - BLOCK_TAIL_LEN)))
#define DOG_ASSERT()\
{\

View File

@ -213,7 +213,6 @@ portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux);
#define portEXIT_CRITICAL_ISR(mux) vPortCPUReleaseMutex(mux)
#endif
// Cleaner and preferred solution allows nested interrupts disabling and restoring via local registers or stack.
// They can be called from interrupts too.
//NOT SMP-COMPATIBLE! Use only if all you want is to disable the interrupts locally!

View File

@ -600,7 +600,7 @@ void *xRingbufferReceiveUpToFromISR(RingbufHandle_t ringbuf, size_t *item_size,
configASSERT(rb);
configASSERT(rb->flags & flag_bytebuf);
portENTER_CRITICAL_ISR(&rb->mux);
itemData=rb->getItemFromRingbufImpl(rb, item_size, 0);
itemData=rb->getItemFromRingbufImpl(rb, item_size, wanted_size);
portEXIT_CRITICAL_ISR(&rb->mux);
return (void*)itemData;
}

View File

@ -369,7 +369,7 @@ PRIVILEGED_DATA static portMUX_TYPE xTickCountMutex = portMUX_INITIALIZER_UNLOCK
\
/* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \
the same priority get an equal share of the processor time. */ \
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB[ xPortGetCoreID() ], &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); \
listGET_OWNER_OF_NEXT_ENTRY( xTaskGetCurrentTaskHandle(), &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); \
} /* taskSELECT_HIGHEST_PRIORITY_TASK */
/*-----------------------------------------------------------*/
@ -398,7 +398,7 @@ PRIVILEGED_DATA static portMUX_TYPE xTickCountMutex = portMUX_INITIALIZER_UNLOCK
/* Find the highest priority queue that contains ready tasks. */ \
portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \
configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB[ xPortGetCoreID() ], &( pxReadyTasksLists[ uxTopPriority ] ) ); \
listGET_OWNER_OF_NEXT_ENTRY( xTaskGetCurrentTaskHandle(), &( pxReadyTasksLists[ uxTopPriority ] ) ); \
} /* taskSELECT_HIGHEST_PRIORITY_TASK() */
/*-----------------------------------------------------------*/
@ -456,7 +456,7 @@ count overflows. */
* see if the parameter is NULL and returns a pointer to the appropriate TCB.
*/
/* ToDo: See if this still works for multicore. */
#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( TCB_t * ) pxCurrentTCB[ xPortGetCoreID() ] : ( TCB_t * ) ( pxHandle ) )
#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( TCB_t * ) xTaskGetCurrentTaskHandle() : ( TCB_t * ) ( pxHandle ) )
/* The item value of the event list item is normally used to hold the priority
of the task to which it belongs (coded to allow it to be held in reverse
@ -631,9 +631,11 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
*/
void taskYIELD_OTHER_CORE( BaseType_t xCoreID, UBaseType_t uxPriority )
{
TCB_t *curTCB = xTaskGetCurrentTaskHandle();
BaseType_t i;
if (xCoreID != tskNO_AFFINITY) {
if ( pxCurrentTCB[ xCoreID ]->uxPriority < uxPriority ) {
if ( curTCB->uxPriority < uxPriority ) {
vPortYieldOtherCore( xCoreID );
}
}
@ -1039,6 +1041,7 @@ UBaseType_t x;
static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode, const BaseType_t xCoreID )
{
TCB_t *curTCB;
BaseType_t i;
/* Ensure interrupts don't access the task lists while the lists are being
@ -1111,23 +1114,25 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
portSETUP_TCB( pxNewTCB );
}
curTCB = pxCurrentTCB[ xPortGetCoreID() ];
taskEXIT_CRITICAL(&xTaskQueueMutex);
if( xSchedulerRunning != pdFALSE )
{
taskENTER_CRITICAL(&xTaskQueueMutex);
/* Scheduler is running. If the created task is of a higher priority than an executing task
then it should run now.
ToDo: This only works for the current core. If a task is scheduled on an other processor,
the other processor will keep running the task it's working on, and only switch to the newer
task on a timer interrupt. */
//No mux here, uxPriority is mostly atomic and there's not really any harm if this check misfires.
if( pxCurrentTCB[ xPortGetCoreID() ]->uxPriority < pxNewTCB->uxPriority )
if( curTCB->uxPriority < pxNewTCB->uxPriority )
{
/* Scheduler is running. If the created task is of a higher priority than an executing task
then it should run now.
No mux here, uxPriority is mostly atomic and there's not really any harm if this check misfires.
*/
if( tskCAN_RUN_HERE( xCoreID ) && pxCurrentTCB[ xPortGetCoreID() ]->uxPriority < pxNewTCB->uxPriority )
if( tskCAN_RUN_HERE( xCoreID ) && curTCB->uxPriority < pxNewTCB->uxPriority )
{
taskYIELD_IF_USING_PREEMPTION();
}
@ -1143,6 +1148,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
{
mtCOVERAGE_TEST_MARKER();
}
taskEXIT_CRITICAL(&xTaskQueueMutex);
}
else
{
@ -1409,11 +1415,12 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
eTaskState eReturn;
List_t *pxStateList;
const TCB_t * const pxTCB = ( TCB_t * ) xTask;
TCB_t * curTCB = xTaskGetCurrentTaskHandle();
UNTESTED_FUNCTION();
configASSERT( pxTCB );
if( pxTCB == pxCurrentTCB[ xPortGetCoreID() ] )
if( pxTCB == curTCB )
{
/* The task calling this function is querying its own state. */
eReturn = eRunning;
@ -1691,6 +1698,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
void vTaskSuspend( TaskHandle_t xTaskToSuspend )
{
TCB_t *pxTCB;
TCB_t *curTCB;
UNTESTED_FUNCTION();
taskENTER_CRITICAL(&xTaskQueueMutex);
@ -1723,10 +1731,11 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
}
vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
curTCB = pxCurrentTCB[ xPortGetCoreID() ];
}
taskEXIT_CRITICAL(&xTaskQueueMutex);
if( pxTCB == pxCurrentTCB[ xPortGetCoreID() ] )
if( pxTCB == curTCB )
{
if( xSchedulerRunning != pdFALSE )
{
@ -2034,7 +2043,7 @@ void vTaskEndScheduler( void )
//Return global reent struct if FreeRTOS isn't running,
struct _reent* __getreent() {
//No lock needed because if this changes, we won't be running anymore.
TCB_t *currTask=pxCurrentTCB[ xPortGetCoreID() ];
TCB_t *currTask=xTaskGetCurrentTaskHandle();
if (currTask==NULL) {
//No task running. Return global struct.
return _GLOBAL_REENT;
@ -2052,7 +2061,11 @@ void vTaskSuspendAll( void )
BaseType_t. Please read Richard Barry's reply in the following link to a
post in the FreeRTOS support forum before reporting this as a bug! -
http://goo.gl/wu4acr */
unsigned state;
state = portENTER_CRITICAL_NESTED();
++uxSchedulerSuspended[ xPortGetCoreID() ];
portEXIT_CRITICAL_NESTED(state);
}
/*----------------------------------------------------------*/
@ -2595,7 +2608,7 @@ BaseType_t xSwitchRequired = pdFALSE;
/* If xTask is NULL then we are setting our own task hook. */
if( xTask == NULL )
{
xTCB = ( TCB_t * ) pxCurrentTCB[ xPortGetCoreID() ];
xTCB = ( TCB_t * ) xTaskGetCurrentTaskHandle();
}
else
{
@ -2626,7 +2639,7 @@ BaseType_t xSwitchRequired = pdFALSE;
/* If xTask is NULL then we are calling our own task hook. */
if( xTask == NULL )
{
xTCB = ( TCB_t * ) pxCurrentTCB[ xPortGetCoreID() ];
xTCB = ( TCB_t * ) xTaskGetCurrentTaskHandle();
}
else
{
@ -3387,8 +3400,8 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS )
{
pxTCB = prvGetTCBFromHandle( xTaskToSet );
taskENTER_CRITICAL(&xTaskQueueMutex);
pxTCB = prvGetTCBFromHandle( xTaskToSet );
pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue;
pxTCB->pvThreadLocalStoragePointersDelCallback[ xIndex ] = xDelCallback;
taskEXIT_CRITICAL(&xTaskQueueMutex);
@ -3408,8 +3421,10 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS )
{
taskENTER_CRITICAL(&xTaskQueueMutex);
pxTCB = prvGetTCBFromHandle( xTaskToSet );
pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue;
taskEXIT_CRITICAL(&xTaskQueueMutex);
}
}
#endif /* configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS */
@ -3496,26 +3511,23 @@ static void prvCheckTasksWaitingTermination( void )
/* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
too often in the idle task. */
taskENTER_CRITICAL(&xTaskQueueMutex);
while( uxTasksDeleted > ( UBaseType_t ) 0U )
{
taskENTER_CRITICAL(&xTaskQueueMutex);
{
xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
}
taskEXIT_CRITICAL(&xTaskQueueMutex);
if( xListIsEmpty == pdFALSE )
{
TCB_t *pxTCB;
taskENTER_CRITICAL(&xTaskQueueMutex);
{
pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
--uxCurrentNumberOfTasks;
--uxTasksDeleted;
}
taskEXIT_CRITICAL(&xTaskQueueMutex);
#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
{
@ -3535,7 +3547,8 @@ static void prvCheckTasksWaitingTermination( void )
{
mtCOVERAGE_TEST_MARKER();
}
}
}
taskEXIT_CRITICAL(&xTaskQueueMutex);
}
#endif /* vTaskDelete */
}
@ -3805,11 +3818,11 @@ TCB_t *pxTCB;
TaskHandle_t xTaskGetCurrentTaskHandle( void )
{
TaskHandle_t xReturn;
unsigned state;
/* A critical section is not required as this is not called from
an interrupt and the current TCB will always be the same for any
individual execution thread. */
state = portENTER_CRITICAL_NESTED();
xReturn = pxCurrentTCB[ xPortGetCoreID() ];
portEXIT_CRITICAL_NESTED(state);
return xReturn;
}
@ -3835,7 +3848,9 @@ TCB_t *pxTCB;
BaseType_t xTaskGetSchedulerState( void )
{
BaseType_t xReturn;
unsigned state;
state = portENTER_CRITICAL_NESTED();
if( xSchedulerRunning == pdFALSE )
{
xReturn = taskSCHEDULER_NOT_STARTED;
@ -3851,6 +3866,7 @@ TCB_t *pxTCB;
xReturn = taskSCHEDULER_SUSPENDED;
}
}
portEXIT_CRITICAL_NESTED(state);
return xReturn;
}
@ -4386,6 +4402,8 @@ TickType_t uxReturn;
void *pvTaskIncrementMutexHeldCount( void )
{
TCB_t *curTCB;
/* If xSemaphoreCreateMutex() is called before any tasks have been created
then pxCurrentTCB will be NULL. */
taskENTER_CRITICAL(&xTaskQueueMutex);
@ -4393,9 +4411,10 @@ TickType_t uxReturn;
{
( pxCurrentTCB[ xPortGetCoreID() ]->uxMutexesHeld )++;
}
curTCB = pxCurrentTCB[ xPortGetCoreID() ];
taskEXIT_CRITICAL(&xTaskQueueMutex);
return pxCurrentTCB[ xPortGetCoreID() ];
return curTCB;
}
#endif /* configUSE_MUTEXES */

View File

@ -34,7 +34,7 @@ static void task_event_group_call_response(void *param)
printf("Task %d done\n", task_num);
/* Delay is due to not-yet-fixed bug with deleting tasks at same time */
vTaskDelay(100 / portTICK_RATE_MS);
vTaskDelay(100 / portTICK_PERIOD_MS);
vTaskDelete(NULL);
}
@ -85,7 +85,7 @@ static void task_test_sync(void *param)
printf("Done %d = %x\n", task_num, after_done);
/* Delay is due to not-yet-fixed bug with deleting tasks at same time */
vTaskDelay(100 / portTICK_RATE_MS);
vTaskDelay(100 / portTICK_PERIOD_MS);
vTaskDelete(NULL);
}

View File

@ -713,7 +713,7 @@ _xt_user_exc:
rsr a2, EXCCAUSE /* recover exc cause */
movi a3, _xt_exception_table
get_percpu_entry_for a3, a4
get_percpu_entry_for a2, a4
addx4 a4, a2, a3 /* a4 = address of exception table entry */
l32i a4, a4, 0 /* a4 = handler address */
#ifdef __XTENSA_CALL0_ABI__

View File

@ -49,6 +49,19 @@ config LWIP_DHCP_MAX_NTP_SERVERS
First argument of sntp_setserver/sntp_setservername functions
is limited to this value.
config LWIP_IP_FRAG
bool "Enable fragment outgoing IP packets"
default 0
help
Enabling this option allows fragmenting outgoing IP packets if their size
exceeds MTU.
config LWIP_IP_REASSEMBLY
bool "Enable reassembly incoming fragmented IP packets"
default 0
help
Enabling this option allows reassemblying incoming fragmented IP packets.
endmenu

View File

@ -268,12 +268,14 @@ static u8_t *add_offer_options(u8_t *optptr)
tcpip_adapter_get_ip_info(ESP_IF_WIFI_AP, &if_ip);
*optptr++ = DHCP_OPTION_ROUTER;
*optptr++ = 4;
*optptr++ = ip4_addr1(&if_ip.gw);
*optptr++ = ip4_addr2(&if_ip.gw);
*optptr++ = ip4_addr3(&if_ip.gw);
*optptr++ = ip4_addr4(&if_ip.gw);
if (!ip4_addr_isany_val(if_ip.gw)) {
*optptr++ = DHCP_OPTION_ROUTER;
*optptr++ = 4;
*optptr++ = ip4_addr1(&if_ip.gw);
*optptr++ = ip4_addr2(&if_ip.gw);
*optptr++ = ip4_addr3(&if_ip.gw);
*optptr++ = ip4_addr4(&if_ip.gw);
}
}
#ifdef USE_DNS

View File

@ -80,6 +80,7 @@
#if ESP_LWIP
#include "esp_wifi_internal.h"
#include "esp_eth.h"
#endif
#define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))
@ -351,7 +352,8 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
p->flags = 0;
#if ESP_LWIP
p->eb = NULL;
p->user_buf = NULL;
p->user_flag = PBUF_USER_FLAG_OWNER_NULL;
#endif
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
@ -720,9 +722,13 @@ pbuf_free(struct pbuf *p)
} else if (type == PBUF_ROM || type == PBUF_REF) {
#if ESP_LWIP
if (type == PBUF_REF && p->eb != NULL ) esp_wifi_internal_free_rx_buffer(p->eb);
if (type == PBUF_REF && p->user_flag == PBUF_USER_FLAG_OWNER_WIFI ) {
esp_wifi_internal_free_rx_buffer(p->user_buf);
}
if (type == PBUF_REF && p->user_flag == PBUF_USER_FLAG_OWNER_ETH ) {
esp_eth_free_rx_buf(p->user_buf);
}
#endif
memp_free(MEMP_PBUF, p);
/* type == PBUF_RAM */
} else {

View File

@ -105,6 +105,12 @@ typedef enum {
/** indicates this pbuf includes a TCP FIN flag */
#define PBUF_FLAG_TCP_FIN 0x20U
#if ESP_LWIP
#define PBUF_USER_FLAG_OWNER_NULL 0
#define PBUF_USER_FLAG_OWNER_WIFI 1
#define PBUF_USER_FLAG_OWNER_ETH 2
#endif
struct pbuf {
/** next pbuf in singly linked pbuf chain */
struct pbuf *next;
@ -138,7 +144,8 @@ struct pbuf {
u16_t ref;
#if ESP_LWIP
void *eb;
void *user_buf;
u8_t user_flag;
#endif
};

View File

@ -154,14 +154,14 @@
* this option does not affect outgoing packet sizes, which can be controlled
* via IP_FRAG.
*/
#define IP_REASSEMBLY 0
#define IP_REASSEMBLY CONFIG_LWIP_IP_REASSEMBLY
/**
* IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note
* that this option does not affect incoming packet sizes, which can be
* controlled via IP_REASSEMBLY.
*/
#define IP_FRAG 0
#define IP_FRAG CONFIG_LWIP_IP_FRAG
/**
* IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally)

View File

@ -164,9 +164,9 @@ sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
StartTime = xTaskGetTickCount();
if (timeout != 0) {
if (xSemaphoreTake(*sem, timeout / portTICK_RATE_MS) == pdTRUE) {
if (xSemaphoreTake(*sem, timeout / portTICK_PERIOD_MS) == pdTRUE) {
EndTime = xTaskGetTickCount();
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
Elapsed = (EndTime - StartTime) * portTICK_PERIOD_MS;
if (Elapsed == 0) {
Elapsed = 1;
@ -180,7 +180,7 @@ sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
while (xSemaphoreTake(*sem, portMAX_DELAY) != pdTRUE);
EndTime = xTaskGetTickCount();
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
Elapsed = (EndTime - StartTime) * portTICK_PERIOD_MS;
if (Elapsed == 0) {
Elapsed = 1;
@ -293,9 +293,9 @@ sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
sys_mutex_lock(&(*mbox)->lock);
if (timeout != 0) {
if (pdTRUE == xQueueReceive((*mbox)->os_mbox, &(*msg), timeout / portTICK_RATE_MS)) {
if (pdTRUE == xQueueReceive((*mbox)->os_mbox, &(*msg), timeout / portTICK_PERIOD_MS)) {
EndTime = xTaskGetTickCount();
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
Elapsed = (EndTime - StartTime) * portTICK_PERIOD_MS;
if (Elapsed == 0) {
Elapsed = 1;
@ -323,7 +323,7 @@ sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
}
EndTime = xTaskGetTickCount();
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
Elapsed = (EndTime - StartTime) * portTICK_PERIOD_MS;
if (Elapsed == 0) {
Elapsed = 1;
@ -566,7 +566,7 @@ void sys_thread_sem_deinit(void)
void sys_delay_ms(uint32_t ms)
{
vTaskDelay(ms/portTICK_RATE_MS);
vTaskDelay(ms / portTICK_PERIOD_MS);
}

View File

@ -113,7 +113,8 @@ ethernet_low_level_output(struct netif *netif, struct pbuf *p)
esp_interface_t eth_if = tcpip_adapter_get_esp_if(netif);
if (eth_if != ESP_IF_ETH) {
printf("eth_if=%d netif=%p pbuf=%p len=%d\n", eth_if, netif, p, p->len);
LWIP_DEBUGF(NETIF_DEBUG,("eth_if=%d netif=%p pbuf=%p len=%d\n", eth_if, netif, p, p->len));
return ERR_IF;
}
@ -134,7 +135,6 @@ ethernet_low_level_output(struct netif *netif, struct pbuf *p)
}
}
//printf("netif=%p pbuf=%p len=%d\n", netif, p, p->len);
return esp_eth_tx(q->payload, pbuf_x_len);
#else
for(q = p; q != NULL; q = q->next) {
@ -160,7 +160,7 @@ ethernetif_input(struct netif *netif, void *buffer, uint16_t len)
if(buffer== NULL || netif == NULL)
goto _exit;
#if CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE
p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
if (p == NULL) {
//g_rx_alloc_pbuf_fail_cnt++;
@ -168,12 +168,28 @@ ethernetif_input(struct netif *netif, void *buffer, uint16_t len)
}
memcpy(p->payload, buffer, len);
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
pbuf_free(p);
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
pbuf_free(p);
}
#else
p = pbuf_alloc(PBUF_RAW, len, PBUF_REF);
if (p == NULL){
return;
}
p->payload = buffer;
p->user_flag = PBUF_USER_FLAG_OWNER_ETH;
p->user_buf = buffer;
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
p->user_flag = PBUF_USER_FLAG_OWNER_NULL;
pbuf_free(p);
}
#endif
_exit:
;
}

View File

@ -176,7 +176,8 @@ wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb)
return;
}
p->payload = buffer;
p->eb = eb;
p->user_buf = eb;
p->user_flag = PBUF_USER_FLAG_OWNER_WIFI;
#endif
/* full packet send to tcpip_thread to process */

View File

@ -22,15 +22,6 @@
#include "esp_attr.h"
#include "freertos/FreeRTOS.h"
void IRAM_ATTR abort()
{
do
{
__asm__ ("break 0,0");
*((int*) 0) = 0;
} while(true);
}
void* IRAM_ATTR _malloc_r(struct _reent *r, size_t size)
{
return pvPortMalloc(size);

View File

@ -21,7 +21,7 @@ PARTITION_TABLE_CSV_PATH := $(call dequote,$(abspath $(PARTITION_TABLE_ROOT)/$(s
PARTITION_TABLE_BIN := $(BUILD_DIR_BASE)/$(notdir $(PARTITION_TABLE_CSV_PATH:.csv=.bin))
ifdef CONFIG_SECURE_BOOT_ENABLED
ifdef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
PARTITION_TABLE_BIN_UNSIGNED := $(PARTITION_TABLE_BIN:.bin=-unsigned.bin)
# add an extra signing step for secure partition table
$(PARTITION_TABLE_BIN): $(PARTITION_TABLE_BIN_UNSIGNED) $(SDKCONFIG_MAKEFILE) $(SECURE_BOOT_SIGNING_KEY)

View File

@ -77,7 +77,7 @@ static void IRAM_ATTR spi_flash_mmap_init()
}
}
esp_err_t IRAM_ATTR spi_flash_mmap(uint32_t src_addr, size_t size, spi_flash_mmap_memory_t memory,
esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_memory_t memory,
const void** out_ptr, spi_flash_mmap_handle_t* out_handle)
{
esp_err_t ret;

View File

@ -78,13 +78,13 @@ esp_err_t spi_flash_erase_range(size_t start_address, size_t size);
* @note If source address is in DROM, this function will return
* ESP_ERR_INVALID_ARG.
*
* @param dest destination address in Flash. Must be a multiple of 4 bytes.
* @param src pointer to the source buffer.
* @param size length of data, in bytes. Must be a multiple of 4 bytes.
* @param dest_addr destination address in Flash. Must be a multiple of 4 bytes.
* @param src pointer to the source buffer.
* @param size length of data, in bytes. Must be a multiple of 4 bytes.
*
* @return esp_err_t
*/
esp_err_t spi_flash_write(size_t dest, const void *src, size_t size);
esp_err_t spi_flash_write(size_t dest_addr, const void *src, size_t size);
/**
@ -97,24 +97,24 @@ esp_err_t spi_flash_write(size_t dest, const void *src, size_t size);
* @note If source address is in DROM, this function will return
* ESP_ERR_INVALID_ARG.
*
* @param dest destination address in Flash. Must be a multiple of 32 bytes.
* @param src pointer to the source buffer.
* @param size length of data, in bytes. Must be a multiple of 32 bytes.
* @param dest_addr destination address in Flash. Must be a multiple of 32 bytes.
* @param src pointer to the source buffer.
* @param size length of data, in bytes. Must be a multiple of 32 bytes.
*
* @return esp_err_t
*/
esp_err_t spi_flash_write_encrypted(size_t dest, const void *src, size_t size);
esp_err_t spi_flash_write_encrypted(size_t dest_addr, const void *src, size_t size);
/**
* @brief Read data from Flash.
*
* @param src source address of the data in Flash.
* @param dest pointer to the destination buffer
* @param size length of data
* @param src_addr source address of the data in Flash.
* @param dest pointer to the destination buffer
* @param size length of data
*
* @return esp_err_t
*/
esp_err_t spi_flash_read(size_t src, void *dest, size_t size);
esp_err_t spi_flash_read(size_t src_addr, void *dest, size_t size);
/**
* @brief Enumeration which specifies memory space requested in an mmap call
@ -149,7 +149,7 @@ typedef uint32_t spi_flash_mmap_handle_t;
*
* @return ESP_OK on success, ESP_ERR_NO_MEM if pages can not be allocated
*/
esp_err_t spi_flash_mmap(uint32_t src_addr, size_t size, spi_flash_mmap_memory_t memory,
esp_err_t spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_memory_t memory,
const void** out_ptr, spi_flash_mmap_handle_t* out_handle);
/**

View File

@ -25,6 +25,9 @@
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#include "lwip/nd6.h"
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
#include "lwip/dns.h"
#endif
#include "netif/wlanif.h"
#include "netif/ethernetif.h"
@ -213,7 +216,7 @@ esp_err_t tcpip_adapter_set_ip_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_i
tcpip_adapter_dhcp_status_t status;
if (tcpip_if >= TCPIP_ADAPTER_IF_MAX || ip_info == NULL ||
ip4_addr_isany_val(ip_info->ip) || ip4_addr_isany_val(ip_info->netmask) || ip4_addr_isany_val(ip_info->gw)) {
ip4_addr_isany_val(ip_info->ip) || ip4_addr_isany_val(ip_info->netmask)) {
return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
}
@ -229,6 +232,12 @@ esp_err_t tcpip_adapter_set_ip_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_i
if (status != TCPIP_ADAPTER_DHCP_STOPPED) {
return ESP_ERR_TCPIP_ADAPTER_DHCP_NOT_STOPPED;
}
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
u8_t numdns = 0;
for (numdns = 0; numdns < DNS_MAX_SERVERS; numdns ++) {
dns_setserver(numdns, NULL);
}
#endif
}
ip4_addr_copy(esp_ip[tcpip_if].ip, ip_info->ip);

View File

@ -83,8 +83,11 @@ ULP coprocessor instruction defines
.. doxygendefine:: I_DELAY
.. doxygendefine:: I_HALT
.. doxygendefine:: I_END
.. doxygendefine:: I_ST
.. doxygendefine:: I_LD
.. doxygendefine:: I_WR_REG
.. doxygendefine:: I_RD_REG
.. doxygendefine:: I_BL
.. doxygendefine:: I_BGE
.. doxygendefine:: I_BXR

View File

@ -47,6 +47,10 @@ extern "C" {
#define OPCODE_RD_REG 2 /*!< Instruction: read peripheral register (RTC_CNTL/RTC_IO/SARADC) (not implemented yet) */
#define RD_REG_PERIPH_RTC_CNTL 0 /*!< Identifier of RTC_CNTL peripheral for RD_REG and WR_REG instructions */
#define RD_REG_PERIPH_RTC_IO 1 /*!< Identifier of RTC_IO peripheral for RD_REG and WR_REG instructions */
#define RD_REG_PERIPH_SENS 2 /*!< Identifier of SARADC peripheral for RD_REG and WR_REG instructions */
#define OPCODE_I2C 3 /*!< Instruction: read/write I2C (not implemented yet) */
#define OPCODE_DELAY 4 /*!< Instruction: delay (nop) for a given number of cycles */
@ -191,8 +195,8 @@ typedef union {
uint32_t addr : 8; /*!< Address within either RTC_CNTL, RTC_IO, or SARADC */
uint32_t periph_sel : 2; /*!< Select peripheral: RTC_CNTL (0), RTC_IO(1), SARADC(2) */
uint32_t data : 8; /*!< 8 bits of data to write */
uint32_t high : 5; /*!< High bit */
uint32_t low : 5; /*!< Low bit */
uint32_t high : 5; /*!< High bit */
uint32_t opcode : 4; /*!< Opcode (OPCODE_WR_REG) */
} wr_reg; /*!< Format of WR_REG instruction */
@ -200,10 +204,10 @@ typedef union {
uint32_t addr : 8; /*!< Address within either RTC_CNTL, RTC_IO, or SARADC */
uint32_t periph_sel : 2; /*!< Select peripheral: RTC_CNTL (0), RTC_IO(1), SARADC(2) */
uint32_t unused : 8; /*!< Unused */
uint32_t high : 5; /*!< High bit */
uint32_t low : 5; /*!< Low bit */
uint32_t high : 5; /*!< High bit */
uint32_t opcode : 4; /*!< Opcode (OPCODE_WR_REG) */
} rd_reg; /*!< Format of WR_REG instruction */
} rd_reg; /*!< Format of RD_REG instruction */
struct {
uint32_t dreg : 2; /*!< Register where to store ADC result */
@ -256,6 +260,8 @@ typedef union {
} ulp_insn_t;
_Static_assert(sizeof(ulp_insn_t) == 4, "ULP coprocessor instruction size should be 4 bytes");
/**
* Delay (nop) for a given number of cycles
*/
@ -271,6 +277,67 @@ typedef union {
.unused = 0, \
.opcode = OPCODE_HALT } }
/**
* Map SoC peripheral register to periph_sel field of RD_REG and WR_REG
* instructions.
*
* @param reg peripheral register in RTC_CNTL_, RTC_IO_, SENS_ peripherals.
* @return periph_sel value for the peripheral to which this register belongs.
*/
static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
uint32_t ret = 3;
if (reg < DR_REG_RTCCNTL_BASE) {
assert(0 && "invalid register base");
} else if (reg < DR_REG_RTCIO_BASE) {
ret = RD_REG_PERIPH_RTC_CNTL;
} else if (reg < DR_REG_SENS_BASE) {
ret = RD_REG_PERIPH_RTC_IO;
} else if (reg < DR_REG_RTCMEM0_BASE){
ret = RD_REG_PERIPH_SENS;
} else {
assert(0 && "invalid register base");
}
return ret;
}
/**
* Write literal value to a peripheral register
*
* reg[high_bit : low_bit] = val
* This instruction can access RTC_CNTL_, RTC_IO_, and SENS_ peripheral registers.
*/
#define I_WR_REG(reg, low_bit, high_bit, val) {.wr_reg = {\
.addr = reg & 0xff, \
.periph_sel = SOC_REG_TO_ULP_PERIPH_SEL(reg), \
.data = val, \
.low = low_bit, \
.high = high_bit, \
.opcode = OPCODE_WR_REG } }
/**
* Read from peripheral register into R0
*
* R0 = reg[high_bit : low_bit]
* This instruction can access RTC_CNTL_, RTC_IO_, and SENS_ peripheral registers.
*/
#define I_RD_REG(reg, low_bit, high_bit, val) {.wr_reg = {\
.addr = reg & 0xff, \
.periph_sel = SOC_REG_TO_ULP_PERIPH_SEL(reg), \
.unused = 0, \
.low = low_bit, \
.high = high_bit, \
.opcode = OPCODE_RD_REG } }
/**
* End program.
*
* If wake == 1, wake up main CPU.
*/
#define I_END(wake) { .end = { \
.wakeup = wake, \
.unused = 0, \
.sub_opcode = SUB_OPCODE_END, \
.opcode = OPCODE_END } }
/**
* Store value from register reg_val into RTC memory.
@ -541,7 +608,7 @@ typedef union {
#define I_ANDI(reg_dest, reg_src, imm_) { .alu_imm = { \
.dreg = reg_dest, \
.sreg = reg_src, \
.imm = reg_imm_, \
.imm = imm_, \
.unused = 0, \
.sel = ALU_SEL_AND, \
.sub_opcode = SUB_OPCODE_ALU_IMM, \

View File

@ -22,12 +22,14 @@
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_deep_sleep.h"
#include "esp32/ulp.h"
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/sens_reg.h"
#include "driver/rtc_io.h"
#include "sdkconfig.h"
@ -92,3 +94,77 @@ TEST_CASE("ulp branch test", "[ulp]")
}
TEST_ASSERT_EQUAL(0, RTC_SLOW_MEM[64]);
}
TEST_CASE("ulp wakeup test", "[ulp]")
{
assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 260 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig");
memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM);
const ulp_insn_t program[] = {
I_MOVI(R1, 1024),
M_LABEL(1),
I_DELAY(32000),
I_SUBI(R1, R1, 1),
M_BXZ(3),
I_RSHI(R3, R1, 5), // R3 = R1 / 32
I_ST(R1, R3, 16),
M_BX(1),
M_LABEL(3),
I_MOVI(R2, 42),
I_MOVI(R3, 15),
I_ST(R2, R3, 0),
I_END(1)
};
size_t size = sizeof(program)/sizeof(ulp_insn_t);
ulp_process_macros_and_load(0, program, &size);
ulp_run(0);
esp_deep_sleep_enable_ulp_wakeup();
esp_deep_sleep_start();
}
TEST_CASE("ulp controls RTC_IO", "[ulp]")
{
assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 260 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig");
memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM);
const ulp_insn_t program[] = {
I_MOVI(R0, 0), // R0 is LED state
I_MOVI(R2, 16), // loop R2 from 16 down to 0
M_LABEL(4),
I_SUBI(R2, R2, 1),
M_BXZ(6),
I_ADDI(R0, R0, 1), // R0 = (R0 + 1) % 2
I_ANDI(R0, R0, 0x1),
M_BL(0, 1), // if R0 < 1 goto 0
M_LABEL(1),
I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 1), // RTC_GPIO12 = 1
M_BX(2), // goto 2
M_LABEL(0), // 0:
I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 0), // RTC_GPIO12 = 0
M_LABEL(2), // 2:
I_MOVI(R1, 100), // loop R1 from 100 down to 0
M_LABEL(3),
I_SUBI(R1, R1, 1),
M_BXZ(5),
I_DELAY(32000), // delay for a while
M_BX(3),
M_LABEL(5),
M_BX(4),
M_LABEL(6),
I_END(1) // wake up the SoC
};
const gpio_num_t led_gpios[] = {
GPIO_NUM_2,
GPIO_NUM_0,
GPIO_NUM_4
};
for (size_t i = 0; i < sizeof(led_gpios)/sizeof(led_gpios[0]); ++i) {
rtc_gpio_init(led_gpios[i]);
rtc_gpio_set_direction(led_gpios[i], RTC_GPIO_MODE_OUTPUT_ONLY);
rtc_gpio_set_level(led_gpios[i], 0);
}
size_t size = sizeof(program)/sizeof(ulp_insn_t);
ulp_process_macros_and_load(0, program, &size);
ulp_run(0);
esp_deep_sleep_enable_ulp_wakeup();
esp_deep_sleep_start();
}

View File

@ -263,8 +263,15 @@ esp_err_t ulp_process_macros_and_load(uint32_t load_addr, const ulp_insn_t* prog
esp_err_t ulp_run(uint32_t entry_point)
{
SET_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_ULP_CP_FORCE_START_TOP_M);
// disable ULP timer
CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
// set entry point
SET_PERI_REG_BITS(SENS_SAR_START_FORCE_REG, SENS_PC_INIT_V, entry_point, SENS_PC_INIT_S);
SET_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_ULP_CP_START_TOP_M);
// disable force start
CLEAR_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_ULP_CP_FORCE_START_TOP_M);
// make sure voltage is raised when RTC 8MCLK is enabled
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FOLW_8M);
// enable ULP timer
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
return ESP_OK;
}

View File

@ -4,20 +4,17 @@ GPIO
Overview
--------
`Instructions`_
The ESP32 chip features 40 physical GPIO pads. Some GPIO pads cannot be used or do not have the corresponding pin on the chip package(refer to technical reference manual ). Each pad can be used as a general purpose I/O or can be connected to an internal peripheral signal.
Note that GPIO6-11 are usually used for SPI flash. GPIO34-39 can only be set as input mode.
Application Example
-------------------
`Instructions`_
GPIO output and input interrupt example: `examples/21_gpio <https://github.com/espressif/esp-idf/tree/master/examples/21_gpio>`_.
API Reference
-------------
`Instructions`_
.. _Instructions: template.html
Header Files
^^^^^^^^^^^^
@ -110,7 +107,8 @@ Macros
Type Definitions
^^^^^^^^^^^^^^^^
.. doxygentypedef:: gpio_event_callback
.. doxygentypedef:: gpio_isr_t
.. doxygentypedef:: gpio_isr_handle_t
Enumerations
^^^^^^^^^^^^
@ -122,6 +120,13 @@ Enumerations
.. doxygenenum:: gpio_pulldown_t
.. doxygenenum:: gpio_pull_mode_t
Structures
^^^^^^^^^^
.. doxygenstruct:: gpio_config_t
:members:
Functions
^^^^^^^^^
@ -136,3 +141,12 @@ Functions
.. doxygenfunction:: gpio_wakeup_enable
.. doxygenfunction:: gpio_wakeup_disable
.. doxygenfunction:: gpio_isr_register
.. doxygenfunction:: gpio_pullup_en
.. doxygenfunction:: gpio_pullup_dis
.. doxygenfunction:: gpio_pulldown_en
.. doxygenfunction:: gpio_pulldown_dis
.. doxygenfunction:: gpio_install_isr_service
.. doxygenfunction:: gpio_uninstall_isr_service
.. doxygenfunction:: gpio_isr_handler_add
.. doxygenfunction:: gpio_isr_handler_remove

82
docs/api/i2c.rst Normal file
View File

@ -0,0 +1,82 @@
I2C
===========
Overview
--------
ESP32 has two I2C controllers which can be set as master mode or slave mode.
Application Example
-------------------
I2C master and slave example: `examples/18_i2c <https://github.com/espressif/esp-idf/tree/master/examples/18_i2c>`_.
API Reference
-------------
Header Files
^^^^^^^^^^^^
* `driver/include/driver/i2c.h <https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/i2c.h>`_
Macros
^^^^^^
.. doxygendefine:: I2C_APB_CLK_FREQ
.. doxygendefine:: I2C_FIFO_LEN
Type Definitions
^^^^^^^^^^^^^^^^
.. doxygentypedef:: i2c_cmd_handle_t
Enumerations
^^^^^^^^^^^^
.. doxygenenum:: i2c_mode_t
.. doxygenenum:: i2c_rw_t
.. doxygenenum:: i2c_trans_mode_t
.. doxygenenum:: i2c_opmode_t
.. doxygenenum:: i2c_port_t
.. doxygenenum:: i2c_addr_mode_t
Structures
^^^^^^^^^^
.. doxygenstruct:: i2c_config_t
:members:
Functions
^^^^^^^^^
.. doxygenfunction:: i2c_driver_install
.. doxygenfunction:: i2c_driver_delete
.. doxygenfunction:: i2c_param_config
.. doxygenfunction:: i2c_reset_tx_fifo
.. doxygenfunction:: i2c_reset_rx_fifo
.. doxygenfunction:: i2c_isr_register
.. doxygenfunction:: i2c_isr_free
.. doxygenfunction:: i2c_set_pin
.. doxygenfunction:: i2c_master_start
.. doxygenfunction:: i2c_master_write_byte
.. doxygenfunction:: i2c_master_write
.. doxygenfunction:: i2c_master_read_byte
.. doxygenfunction:: i2c_master_read
.. doxygenfunction:: i2c_master_stop
.. doxygenfunction:: i2c_master_cmd_begin
.. doxygenfunction:: i2c_slave_write_buffer
.. doxygenfunction:: i2c_slave_read
.. doxygenfunction:: i2c_set_period
.. doxygenfunction:: i2s_get_period
.. doxygenfunction:: i2c_set_start_timing
.. doxygenfunction:: i2c_get_start_timing
.. doxygenfunction:: i2c_set_stop_timing
.. doxygenfunction:: i2c_get_stop_timing
.. doxygenfunction:: i2c_set_data_timing
.. doxygenfunction:: i2c_get_data_timing
.. doxygenfunction:: i2c_set_data_mode
.. doxygenfunction:: i2c_get_data_mode
.. doxygenfunction:: i2c_cmd_link_create
.. doxygenfunction:: i2c_cmd_link_delete

View File

@ -40,10 +40,15 @@ Application Example
*INSTRUCTIONS*
1. Provide one or more practical examples to demonstrate functionality of this API.
2. Break down the code into parts and describe functionality of each part.
3. Provide screenshots if applicable.
1. Prepare one or more practical examples to demonstrate functionality of this API.
2. Each example should follow pattern of projects located in ``esp-idf/examples/`` folder.
3. Place example in this folder complete with ``README.md`` file.
4. Provide overview of demonstrated functionality in ``README.md``.
5. With good overview reader should be able to understand what example does without opening the source code.
6. Depending on complexity of example, break down description of code into parts and provide overview of functionality of each part.
7. Include flow diagram and screenshots of application output if applicable.
8. Finally add in this section synopsis of each example together with link to respective folder in ``esp-idf/examples/``.
API Reference
-------------

View File

@ -94,5 +94,7 @@ Functions
.. doxygenfunction:: uart_write_bytes_with_break
.. doxygenfunction:: uart_read_bytes
.. doxygenfunction:: uart_flush
.. doxygenfunction:: uart_get_buffered_data_len
.. doxygenfunction:: uart_disable_pattern_det_intr
.. doxygenfunction:: uart_enable_pattern_det_intr

View File

@ -107,6 +107,7 @@ Contents:
LED Control <api/ledc>
Remote Control <api/rmt>
Timer <api/timer>
I2C <api/i2c>
Pulse Counter <api/pcnt>
Sigma-delta Modulation <api/sigmadelta>
SPI Flash and Partition APIs <api/spi_flash>

View File

@ -17,7 +17,6 @@ To compile with ESP-IDF you need to get the following packages:
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial
Step 1: Download binary toolchain for the ESP32
==================================================
@ -49,6 +48,16 @@ Alternatively, you may create an alias for the above command. This way you can g
Then when you need the toolchain you can type ``get_esp32`` on the command line and the toolchain will be added to your ``PATH``.
Arch Linux Users
----------------
To run the precompiled gdb (xtensa-esp32-elf-gdb) in Arch Linux requires ncurses 5, but Arch uses ncurses 6. Backwards compatibility libraries are available in AUR_ for native and lib32 configurations:
- https://aur.archlinux.org/packages/ncurses5-compat-libs/
- https://aur.archlinux.org/packages/lib32-ncurses5-compat-libs/
(Alternatively, use crosstool-NG to compile a gdb that links against ncurses 6.)
Alternative Step 1: Compile the toolchain from source using crosstool-NG
========================================================================
@ -156,3 +165,4 @@ Further reading
If you'd like to use the Eclipse IDE instead of running ``make``, check out the Eclipse setup guide in this directory.
.. _AUR: https://wiki.archlinux.org/index.php/Arch_User_Repository

View File

@ -66,7 +66,9 @@ In any case, here are the steps to compile the toolchain yourself.
sudo port install gsed gawk binutils gperf grep gettext ncurses
- with homebrew (*TODO: provide list of packages for homebrew*)
- with homebrew
brew install gnu-sed gawk binutils gperf grep gettext ncurses
Create a case-sensitive filesystem image::

View File

@ -125,5 +125,6 @@ Flashing the partition table
A manual flashing command is also printed as part of ``make partition_table``.
Note that updating the partition table doesn't erase data that may have been stored according to the old partition table. You can use ``make erase_flash`` (or ``esptool.py erase_flash``) to erase the entire flash contents.
.. _secure boot: security/secure-boot.rst

View File

@ -25,7 +25,7 @@ This is a high level overview of the secure boot process. Step by step instructi
1. The options to enable secure boot are provided in the ``make menuconfig`` hierarchy, under "Secure Boot Configuration".
2. Secure Boot Configuration includes "Secure boot signing key", which is a file path. This file is a ECDSA public/private key pair in a PEM format file.
2. Secure Boot defaults to signing images and partition table data during the build process. The "Secure boot private signing key" config item is a file path to a ECDSA public/private key pair in a PEM format file.
3. The software bootloader image is built by esp-idf with secure boot support enabled and the public key (signature verification) portion of the secure boot signing key compiled in. This software bootloader image is flashed at offset 0x1000.
@ -119,6 +119,27 @@ openssl ecparam -name prime256v1 -genkey -noout -out my_secure_boot_signing_key.
Remember that the strength of the secure boot system depends on keeping the signing key private.
Remote Signing of Images
------------------------
For production builds, it can be good practice to use a remote signing server rather than have the signing key on the build machine (which is the default esp-idf secure boot configuration). The espsecure.py command line program can be used to sign app images & partition table data for secure boot, on a remote system.
To use remote signing, disable the option "Sign binaries during build". The private signing key does not need to be present on the build system. However, the public (signature verification) key is required because it is compiled into the bootloader (and can be used to verify image signatures during OTA updates.
To extract the public key from the private key::
espsecure.py extract_public_key --keyfile PRIVATE_SIGNING_KEY PUBLIC_VERIFICATION_KEY
The path to the public signature verification key needs to be specified in the menuconfig under "Secure boot public signature verification key" in order to build the secure bootloader.
After the app image and partition table are built, the build system will print signing steps using espsecure.py::
espsecure.py sign_data --keyfile PRIVATE_SIGNING_KEY BINARY_FILE
The above command appends the image signature to the existing binary. You can use the --output argument to place the binary with signature appended into a separate file::
espsecure.py sign_data --keyfile PRIVATE_SIGNING_KEY --output SIGNED_BINARY_FILE BINARY_FILE
Secure Boot Best Practices
--------------------------

View File

@ -17,7 +17,7 @@ void hello_task(void *pvParameter)
printf("Hello world!\n");
for (int i = 10; i >= 0; i--) {
printf("Restarting in %d seconds...\n", i);
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
printf("Restarting now.\n");
fflush(stdout);

View File

@ -33,10 +33,10 @@ void blink_task(void *pvParameter)
while(1) {
/* Blink off (output low) */
gpio_set_level(BLINK_GPIO, 0);
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
/* Blink on (output high) */
gpio_set_level(BLINK_GPIO, 1);
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}

View File

@ -115,7 +115,7 @@ static void http_get_task(void *pvParameters)
if(err != 0 || res == NULL) {
ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
@ -129,7 +129,7 @@ static void http_get_task(void *pvParameters)
if(s < 0) {
ESP_LOGE(TAG, "... Failed to allocate socket.");
freeaddrinfo(res);
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
ESP_LOGI(TAG, "... allocated socket\r\n");
@ -138,7 +138,7 @@ static void http_get_task(void *pvParameters)
ESP_LOGE(TAG, "... socket connect failed errno=%d", errno);
close(s);
freeaddrinfo(res);
vTaskDelay(4000 / portTICK_RATE_MS);
vTaskDelay(4000 / portTICK_PERIOD_MS);
continue;
}
@ -148,7 +148,7 @@ static void http_get_task(void *pvParameters)
if (write(s, REQUEST, strlen(REQUEST)) < 0) {
ESP_LOGE(TAG, "... socket send failed");
close(s);
vTaskDelay(4000 / portTICK_RATE_MS);
vTaskDelay(4000 / portTICK_PERIOD_MS);
continue;
}
ESP_LOGI(TAG, "... socket send success");
@ -166,7 +166,7 @@ static void http_get_task(void *pvParameters)
close(s);
for(int countdown = 10; countdown >= 0; countdown--) {
ESP_LOGI(TAG, "%d... ", countdown);
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
ESP_LOGI(TAG, "Starting again!");
}

View File

@ -362,7 +362,7 @@ static void https_get_task(void *pvParameters)
for(int countdown = 10; countdown >= 0; countdown--) {
ESP_LOGI(TAG, "%d...", countdown);
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
ESP_LOGI(TAG, "Starting again!");
}

View File

@ -72,7 +72,7 @@ void app_main()
// Restart module
for (int i = 10; i >= 0; i--) {
printf("Restarting in %d seconds...\n", i);
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
printf("Restarting now.\n");
fflush(stdout);

View File

@ -164,7 +164,7 @@ void app_main()
*/
while (1) {
if (gpio_get_level(GPIO_NUM_0) == 0) {
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
if(gpio_get_level(GPIO_NUM_0) == 0) {
err = save_run_time();
if (err != ESP_OK) printf("Error (%d) saving run time blob to NVS!\n", err);
@ -173,6 +173,6 @@ void app_main()
esp_restart();
}
}
vTaskDelay(200 / portTICK_RATE_MS);
vTaskDelay(200 / portTICK_PERIOD_MS);
}
}

View File

@ -0,0 +1,6 @@
# Example: rmt_nec_tx_rx
This example uses the remote control (RMT) peripheral to transmit and receive codes for the NEC infrared remote protocol.
Configuration (pin numbers, etc.) can be modified in top of the main/infrared_nec.c file.

View File

@ -352,7 +352,7 @@ void rmt_nec_tx_task()
rmt_wait_tx_done(channel);
//before we free the data, make sure sending is already done.
free(item);
vTaskDelay(2000 / portTICK_RATE_MS);
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}

View File

@ -30,6 +30,7 @@
#include "bt_trace.h"
#include "bt_types.h"
#include "bta_api.h"
#include "blufi.h"

View File

@ -69,7 +69,7 @@ static esp_err_t blufi_task_post(uint32_t sig, void *par, void *cb, void *arg)
evt.cb = cb;
evt.arg = arg;
if (xQueueSend(xBlufiTaskQueue, &evt, 10 / portTICK_RATE_MS) != pdTRUE) {
if (xQueueSend(xBlufiTaskQueue, &evt, 10 / portTICK_PERIOD_MS) != pdTRUE) {
LOG_ERROR("Blufi Post failed\n");
return ESP_FAIL;
}

View File

@ -46,15 +46,15 @@ const int CONNECTED_BIT = BIT0;
static wifi_config_t sta_config;
static char tmp_ssid[33];
static char tmp_passwd[33];
static char tmp_passwd[65];
static bool confirm = false;
void wifi_set_blue_config(char *ssid, char *passwd)
{
memset(tmp_ssid, 0, 33);
memset(tmp_passwd, 0, 33);
strcpy(tmp_ssid, ssid);
strcpy(tmp_passwd, passwd);
memset(tmp_ssid, 0, sizeof(tmp_ssid));
memset(tmp_passwd, 0, sizeof(tmp_passwd));
strlcpy(tmp_ssid, ssid, sizeof(tmp_ssid));
strlcpy(tmp_passwd, passwd, sizeof(tmp_passwd));
confirm = true;
LOG_DEBUG("confirm true\n");
}
@ -105,8 +105,8 @@ void wifiTestTask(void *pvParameters)
if (confirm) {
confirm = false;
strcpy(sta_config.sta.ssid, tmp_ssid);
strcpy(sta_config.sta.password, tmp_passwd);
memcpy(sta_config.sta.ssid, tmp_ssid, sizeof(sta_config.sta.ssid));
memcpy(sta_config.sta.password, tmp_passwd, sizeof(sta_config.sta.password));
sta_config.sta.bssid_set = 0;
ret = esp_wifi_disconnect();

View File

@ -0,0 +1,3 @@
# Example: timer_group
This example uses the timer group driver to generate timer interrupts at two specified alarm intervals.

View File

@ -83,7 +83,7 @@ void IRAM_ATTR timer_group0_isr(void *para)
uint32_t intr_status = TIMERG0.int_st_timers.val;
timer_event_t evt;
if((intr_status & BIT(timer_idx)) && timer_idx == TIMER_0) {
/*Timer0 is an example that don't reload counter value*/
/*Timer0 is an example that doesn't reload counter value*/
TIMERG0.hw_timer[timer_idx].update = 1;
/* We don't call a API here because they are not declared with IRAM_ATTR.
@ -197,9 +197,9 @@ void tg0_timer1_init()
*/
void app_main()
{
timer_queue = xQueueCreate(10, sizeof(timer_event_t));
tg0_timer0_init();
tg0_timer1_init();
timer_queue = xQueueCreate(10, sizeof(timer_event_t));
xTaskCreate(timer_evt_task, "timer_evt_task", 1024, NULL, 5, NULL);
xTaskCreate(timer_evt_task, "timer_evt_task", 2048, NULL, 5, NULL);
}

View File

@ -0,0 +1,14 @@
# Example: pcnt
This example uses the pulse counter module (PCNT) to count the rising edges of pulses generated by the LED Controller module (LEDC).
By default GPIO18 is used as output pin, GPIO4 is used as pulse input pin and GPIO5 is used as control input pin. This configuration (pin numbers, etc.) can be modified in top of the main/pcnt_test.c file.
* Open serial port to view the message printed on your screen
* To do this test, you should connect GPIO18 with GPIO4
* GPIO5 is the control signal, you can leave it floating with internal pulled up, or connect it to ground. HIGH = Count increases, LOW = count decreases.
* An interrupt is configured to trigger when the count reaches threshold values.
* The counter will reset when it reaches the limit values.

View File

@ -36,14 +36,14 @@
* When counter value reaches thresh1 or thresh0 value, it will trigger interrupt.
* When counter value reaches l_lim value or h_lim value, counter value will be reset to zero and trigger interrupt.
*/
#define PCNT_TEST_UNIT PCNT_UNIT_0
#define PCNT_H_LIM_VAL (10)
#define PCNT_L_LIM_VAL (-10)
#define PCNT_THRESH1_VAL (5)
#define PCNT_THRESH0_VAL (-5)
#define PCNT_INPUT_SIG_IO (4)
#define PCNT_INPUT_CTRL_IO (5)
#define LEDC_OUPUT_IO (18)
#define PCNT_TEST_UNIT PCNT_UNIT_0
#define PCNT_H_LIM_VAL 10
#define PCNT_L_LIM_VAL -10
#define PCNT_THRESH1_VAL 5
#define PCNT_THRESH0_VAL -5
#define PCNT_INPUT_SIG_IO 4 /* Pulse Input GPIO */
#define PCNT_INPUT_CTRL_IO 5 /* Control GPIO HIGH=count up, LOW=count down */
#define LEDC_OUTPUT_IO 18 /* Output GPIO */
xQueueHandle pcnt_evt_queue; /*A queue to handle pulse counter event*/
@ -96,8 +96,8 @@ void IRAM_ATTR pcnt_intr_handler(void* arg)
static void ledc_init(void)
{
ledc_channel_config_t ledc_channel;
/*use GPIO18 as output pin*/
ledc_channel.gpio_num = LEDC_OUPUT_IO;
/*use LEDC_OUTPUT_IO as output pin*/
ledc_channel.gpio_num = LEDC_OUTPUT_IO;
/*LEDC high speed mode */
ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;
/*use LEDC channel 1*/
@ -125,9 +125,9 @@ static void ledc_init(void)
static void pcnt_init(void)
{
pcnt_config_t pcnt_config = {
/*Set GPIO4 as pulse input gpio */
/*Set PCNT_INPUT_SIG_IO as pulse input gpio */
.pulse_gpio_num = PCNT_INPUT_SIG_IO,
/*set gpio5 as control gpio */
/*set PCNT_INPUT_CTRL_IO as control gpio */
.ctrl_gpio_num = PCNT_INPUT_CTRL_IO,
/*Choose channel 0 */
.channel = PCNT_CHANNEL_0,
@ -196,7 +196,7 @@ void app_main()
portBASE_TYPE res;
while(1)
{
res = xQueueReceive(pcnt_evt_queue, &evt, 1000 / portTICK_RATE_MS);
res = xQueueReceive(pcnt_evt_queue, &evt, 1000 / portTICK_PERIOD_MS);
if(res == pdTRUE) {
pcnt_get_counter_value(PCNT_TEST_UNIT, &count);
printf("Event PCNT unit[%d]; cnt: %d\n", evt.unit, count);

View File

@ -32,30 +32,64 @@
#include "tcpip_adapter.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
#include "tlk110_phy.h"
static const char *TAG = "eth_demo";
#define DEFAULT_PHY_CONFIG (AUTO_MDIX_ENABLE|AUTO_NEGOTIATION_ENABLE|AN_1|AN_0|LED_CFG)
void phy_tlk110_check_phy_init(void)
{
while((esp_eth_smi_read(BASIC_MODE_STATUS_REG) & AUTO_NEGOTIATION_COMPLETE ) != AUTO_NEGOTIATION_COMPLETE)
{};
while((esp_eth_smi_read(PHY_STATUS_REG) & AUTO_NEGTIATION_STATUS ) != AUTO_NEGTIATION_STATUS)
{};
while((esp_eth_smi_read(CABLE_DIAGNOSTIC_CONTROL_REG) & DIAGNOSTIC_DONE ) != DIAGNOSTIC_DONE)
{};
}
eth_speed_mode_t phy_tlk110_get_speed_mode(void)
{
if((esp_eth_smi_read(PHY_STATUS_REG) & SPEED_STATUS ) != SPEED_STATUS) {
return ETH_SPEED_MODE_100M;
} else {
return ETH_SPEED_MODE_10M;
}
}
eth_duplex_mode_t phy_tlk110_get_duplex_mode(void)
{
if((esp_eth_smi_read(PHY_STATUS_REG) & DUPLEX_STATUS ) == DUPLEX_STATUS) {
return ETH_MDOE_FULLDUPLEX;
} else {
return ETH_MODE_HALFDUPLEX;
}
}
bool phy_tlk110_check_phy_link_status(void)
{
return ((esp_eth_smi_read(BASIC_MODE_STATUS_REG) & LINK_STATUS) == LINK_STATUS );
}
void phy_tlk110_init(void)
{
esp_eth_smi_write(0x1f, 0x8000);
ets_delay_us(20000);
esp_eth_smi_write(PHY_RESET_CONTROL_REG, SOFTWARE_RESET);
while (esp_eth_smi_read(0x2) != 0x2000) {
while (esp_eth_smi_read(PHY_IDENTIFIER_REG) != OUI_MSB_21TO6_DEF) {
}
esp_eth_smi_write(0x9, 0x7400);
esp_eth_smi_write(0x9, 0xf400);
ets_delay_us(20000);
esp_eth_smi_write(SOFTWARE_STAP_CONTROL_REG, DEFAULT_PHY_CONFIG |SW_STRAP_CONFIG_DONE);
ets_delay_us(300);
}
void eth_gpio_config_rmii(void)
{
//txd0 to gpio19 ,can not change
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, 5);
//rx_en to gpio21 ,can not change
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO21_U, 5);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_EMAC_TXD0);
//tx_en to gpio21 ,can not change
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO21_U, FUNC_GPIO21_EMAC_TX_EN);
//txd1 to gpio22 , can not change
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO22_U, 5);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO22_U, FUNC_GPIO22_EMAC_TXD1);
//rxd0 to gpio25 , can not change
gpio_set_direction(25, GPIO_MODE_INPUT);
//rxd1 to gpio26 ,can not change
@ -74,11 +108,11 @@ void eth_task(void *pvParameter)
{
tcpip_adapter_ip_info_t ip;
memset(&ip, 0, sizeof(tcpip_adapter_ip_info_t));
vTaskDelay(2000 / portTICK_RATE_MS);
vTaskDelay(2000 / portTICK_PERIOD_MS);
while (1) {
vTaskDelay(2000 / portTICK_RATE_MS);
vTaskDelay(2000 / portTICK_PERIOD_MS);
if (tcpip_adapter_get_ip_info(ESP_IF_ETH, &ip) == 0) {
ESP_LOGI(TAG, "\n~~~~~~~~~~~\n");
@ -102,8 +136,13 @@ void app_main()
config.phy_init = phy_tlk110_init;
config.gpio_config = eth_gpio_config_rmii;
config.tcpip_input = tcpip_adapter_eth_input;
config.phy_check_init = phy_tlk110_check_phy_init;
config.phy_check_link = phy_tlk110_check_phy_link_status;
config.phy_get_speed_mode = phy_tlk110_get_speed_mode;
config.phy_get_duplex_mode = phy_tlk110_get_duplex_mode;
ret = esp_eth_init(&config);
if(ret == ESP_OK) {
esp_eth_enable();
xTaskCreate(eth_task, "eth_task", 2048, NULL, (tskIDLE_PRIORITY + 2), NULL);

View File

@ -0,0 +1,28 @@
#define BASIC_MODE_STATUS_REG (0x1)
#define AUTO_NEGOTIATION_COMPLETE BIT(5)
#define LINK_STATUS BIT(2)
#define PHY_IDENTIFIER_REG (0x2)
#define OUI_MSB_21TO6_DEF 0x2000
#define SOFTWARE_STAP_CONTROL_REG (0x9)
#define SW_STRAP_CONFIG_DONE BIT(15)
#define AUTO_MDIX_ENABLE BIT(14)
#define AUTO_NEGOTIATION_ENABLE BIT(13)
#define AN_1 BIT(12)
#define AN_0 BIT(11)
#define LED_CFG BIT(10)
#define RMII_ENHANCED_MODE BIT(9)
#define PHY_STATUS_REG (0x10)
#define AUTO_NEGTIATION_STATUS BIT(4)
#define DUPLEX_STATUS BIT(2)
#define SPEED_STATUS BIT(1)
#define CABLE_DIAGNOSTIC_CONTROL_REG (0x1e)
#define DIAGNOSTIC_DONE BIT(1)
#define PHY_RESET_CONTROL_REG (0x1f)
#define SOFTWARE_RESET BIT(15)

9
examples/18_i2c/Makefile Normal file
View File

@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := i2c
include $(IDF_PATH)/make/project.mk

29
examples/18_i2c/README.md Normal file
View File

@ -0,0 +1,29 @@
# I2C Example
* This example will show you how to use I2C module by running two tasks on i2c bus:
* read external i2c sensor, here we use a BH1750 light sensor(GY-30 module) for instance.
* Use one I2C port(master mode) to read or write the other I2C port(slave mode) on one ESP32 chip.
* Pin assignment:
* slave :
* GPIO25 is assigned as the data signal of i2c slave port
* GPIO26 is assigned as the clock signal of i2c slave port
* master:
* GPIO18 is assigned as the data signal of i2c master port
* GPIO19 is assigned as the clock signal of i2c master port
* Connection:
* connect GPIO18 with GPIO25
* connect GPIO19 with GPIO26
* connect sda/scl of sensor with GPIO18/GPIO19
* no need to add external pull-up resistors, driver will enable internal pull-up resistors.
* Test items:
* read the sensor data, if connected.
* i2c master(ESP32) will write data to i2c slave(ESP32).
* i2c master(ESP32) will read data from i2c slave(ESP32).

View File

@ -0,0 +1,3 @@
#
# Main Makefile. This is basically the same as a component makefile.
#

View File

@ -0,0 +1,303 @@
/* i2c - Example
For other examples please check:
https://github.com/espressif/esp-idf/tree/master/examples
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "driver/i2c.h"
/**
* TEST CODE BRIEF
*
* This example will show you how to use I2C module by running two tasks on i2c bus:
*
* - read external i2c sensor, here we use a BH1750 light sensor(GY-30 module) for instance.
* - Use one I2C port(master mode) to read or write the other I2C port(slave mode) on one ESP32 chip.
*
* Pin assignment:
*
* - slave :
* GPIO25 is assigned as the data signal of i2c slave port
* GPIO26 is assigned as the clock signal of i2c slave port
* - master:
* GPIO18 is assigned as the data signal of i2c master port
* GPIO19 is assigned as the clock signal of i2c master port
*
* Connection:
*
* - connect GPIO18 with GPIO25
* - connect GPIO19 with GPIO26
* - connect sda/scl of sensor with GPIO18/GPIO19
* - no need to add external pull-up resistors, driver will enable internal pull-up resistors.
*
* Test items:
*
* - read the sensor data, if connected.
* - i2c master(ESP32) will write data to i2c slave(ESP32).
* - i2c master(ESP32) will read data from i2c slave(ESP32).
*/
#define DATA_LENGTH 512 /*!<Data buffer length for test buffer*/
#define RW_TEST_LENGTH 129 /*!<Data length for r/w test, any value from 0-DATA_LENGTH*/
#define DELAY_TIME_BETWEEN_ITEMS_MS 1234 /*!< delay time between different test items */
#define I2C_SLAVE_SCL_IO 26 /*!<gpio number for i2c slave clock */
#define I2C_SLAVE_SDA_IO 25 /*!<gpio number for i2c slave data */
#define I2C_SLAVE_NUM I2C_NUM_0 /*!<I2C port number for slave dev */
#define I2C_SLAVE_TX_BUF_LEN (2*DATA_LENGTH) /*!<I2C slave tx buffer size */
#define I2C_SLAVE_RX_BUF_LEN (2*DATA_LENGTH) /*!<I2C slave rx buffer size */
#define I2C_MASTER_SCL_IO 19 /*!< gpio number for I2C master clock */
#define I2C_MASTER_SDA_IO 18 /*!< gpio number for I2C master data */
#define I2C_MASTER_NUM I2C_NUM_1 /*!< I2C port number for master dev */
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
#define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */
#define BH1750_SENSOR_ADDR 0x23 /*!< slave address for BH1750 sensor */
#define BH1750_CMD_START 0x23 /*!< Command to set measure mode */
#define ESP_SLAVE_ADDR 0x28 /*!< ESP32 slave address, you can set any 7bit value */
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
#define ACK_VAL 0x0 /*!< I2C ack value */
#define NACK_VAL 0x1 /*!< I2C nack value */
xSemaphoreHandle print_mux;
/**
* @brief test code to read esp-i2c-slave
* We need to fill the buffer of esp slave device, then master can read them out.
*
* _______________________________________________________________________________________
* | start | slave_addr + rd_bit +ack | read n-1 bytes + ack | read 1 byte + nack | stop |
* --------|--------------------------|----------------------|--------------------|------|
*
*/
esp_err_t i2c_master_read_slave(i2c_port_t i2c_num, uint8_t* data_rd, size_t size)
{
if (size == 0) {
return ESP_OK;
}
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN);
if (size > 1) {
i2c_master_read(cmd, data_rd, size - 1, ACK_VAL);
}
i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
/**
* @brief Test code to write esp-i2c-slave
* Master device write data to slave(both esp32),
* the data will be stored in slave buffer.
* We can read them out from slave buffer.
*
* ___________________________________________________________________
* | start | slave_addr + wr_bit + ack | write n bytes + ack | stop |
* --------|---------------------------|----------------------|------|
*
*/
esp_err_t i2c_master_write_slave(i2c_port_t i2c_num, uint8_t* data_wr, size_t size)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write(cmd, data_wr, size, ACK_CHECK_EN);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
/**
* @brief test code to write esp-i2c-slave
*
* 1. set mode
* _________________________________________________________________
* | start | slave_addr + wr_bit + ack | write 1 byte + ack | stop |
* --------|---------------------------|---------------------|------|
* 2. wait more than 24 ms
* 3. read data
* ______________________________________________________________________________________
* | start | slave_addr + rd_bit + ack | read 1 byte + ack | read 1 byte + nack | stop |
* --------|---------------------------|--------------------|--------------------|------|
*/
esp_err_t i2c_master_sensor_test(i2c_port_t i2c_num, uint8_t* data_h, uint8_t* data_l)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, BH1750_SENSOR_ADDR << 1 | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write_byte(cmd, BH1750_CMD_START, ACK_CHECK_EN);
i2c_master_stop(cmd);
int ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret == ESP_FAIL) {
return ret;
}
vTaskDelay(30 / portTICK_RATE_MS);
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, BH1750_SENSOR_ADDR << 1 | READ_BIT, ACK_CHECK_EN);
i2c_master_read_byte(cmd, data_h, ACK_VAL);
i2c_master_read_byte(cmd, data_l, NACK_VAL);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret == ESP_FAIL) {
return ESP_FAIL;
}
return ESP_OK;
}
/**
* @brief i2c master initialization
*/
void i2c_master_init()
{
int i2c_master_port = I2C_MASTER_NUM;
i2c_config_t conf;
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = I2C_MASTER_SDA_IO;
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_io_num = I2C_MASTER_SCL_IO;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
i2c_param_config(i2c_master_port, &conf);
i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}
/**
* @brief i2c slave initialization
*/
void i2c_slave_init()
{
int i2c_slave_port = I2C_SLAVE_NUM;
i2c_config_t conf_slave;
conf_slave.sda_io_num = I2C_SLAVE_SDA_IO;
conf_slave.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf_slave.scl_io_num = I2C_SLAVE_SCL_IO;
conf_slave.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf_slave.mode = I2C_MODE_SLAVE;
conf_slave.slave.addr_10bit_en = 0;
conf_slave.slave.slave_addr = ESP_SLAVE_ADDR;
i2c_param_config(i2c_slave_port, &conf_slave);
i2c_driver_install(i2c_slave_port, conf_slave.mode, I2C_SLAVE_RX_BUF_LEN, I2C_SLAVE_TX_BUF_LEN, 0);
}
/**
* @brief test function to show buffer
*/
void disp_buf(uint8_t* buf, int len)
{
int i;
for (i = 0; i < len; i++) {
printf("%02x ", buf[i]);
if (( i + 1 ) % 16 == 0) {
printf("\n");
}
}
printf("\n");
}
void i2c_test_task(void* arg)
{
int i = 0;
int ret;
uint32_t task_idx = (uint32_t) arg;
uint8_t* data = (uint8_t*) malloc(DATA_LENGTH);
uint8_t* data_wr = (uint8_t*) malloc(DATA_LENGTH);
uint8_t* data_rd = (uint8_t*) malloc(DATA_LENGTH);
uint8_t sensor_data_h, sensor_data_l;
while (1) {
ret = i2c_master_sensor_test( I2C_MASTER_NUM, &sensor_data_h, &sensor_data_l);
xSemaphoreTake(print_mux, portMAX_DELAY);
printf("*******************\n");
printf("TASK[%d] MASTER READ SENSOR( BH1750 )\n", task_idx);
printf("*******************\n");
if (ret == ESP_OK) {
printf("data_h: %02x\n", sensor_data_h);
printf("data_l: %02x\n", sensor_data_l);
printf("sensor val: %f\n", ( sensor_data_h << 8 | sensor_data_l ) / 1.2);
} else {
printf("No ack, sensor not connected...skip...\n");
}
xSemaphoreGive(print_mux);
vTaskDelay(( DELAY_TIME_BETWEEN_ITEMS_MS * ( task_idx + 1 ) ) / portTICK_RATE_MS);
//---------------------------------------------------
for (i = 0; i < DATA_LENGTH; i++) {
data[i] = i;
}
size_t d_size = i2c_slave_write_buffer(I2C_SLAVE_NUM, data, RW_TEST_LENGTH, 1000 / portTICK_RATE_MS);
if (d_size == 0) {
printf("i2c slave tx buffer full\n");
ret = i2c_master_read_slave(I2C_MASTER_NUM, data_rd, DATA_LENGTH);
} else {
ret = i2c_master_read_slave(I2C_MASTER_NUM, data_rd, RW_TEST_LENGTH);
}
xSemaphoreTake(print_mux, portMAX_DELAY);
printf("*******************\n");
printf("TASK[%d] MASTER READ FROM SLAVE\n", task_idx);
printf("*******************\n");
printf("====TASK[%d] Slave buffer data ====\n", task_idx);
disp_buf(data, d_size);
if (ret == ESP_OK) {
printf("====TASK[%d] Master read ====\n", task_idx);
disp_buf(data_rd, d_size);
} else {
printf("Master read slave error, IO not connected...\n");
}
xSemaphoreGive(print_mux);
vTaskDelay(( DELAY_TIME_BETWEEN_ITEMS_MS * ( task_idx + 1 ) ) / portTICK_RATE_MS);
//---------------------------------------------------
int size;
for (i = 0; i < DATA_LENGTH; i++) {
data_wr[i] = i + 10;
}
//we need to fill the slave buffer so that master can read later
ret = i2c_master_write_slave( I2C_MASTER_NUM, data_wr, RW_TEST_LENGTH);
if (ret == ESP_OK) {
size = i2c_slave_read_buffer( I2C_SLAVE_NUM, data, RW_TEST_LENGTH, 1000 / portTICK_RATE_MS);
}
xSemaphoreTake(print_mux, portMAX_DELAY);
printf("*******************\n");
printf("TASK[%d] MASTER WRITE TO SLAVE\n", task_idx);
printf("*******************\n");
printf("----TASK[%d] Master write ----\n", task_idx);
disp_buf(data_wr, RW_TEST_LENGTH);
if (ret == ESP_OK) {
printf("----TASK[%d] Slave read: [%d] bytes ----\n", task_idx, size);
disp_buf(data, size);
} else {
printf("TASK[%d] Master write slave error, IO not connected....\n", task_idx);
}
xSemaphoreGive(print_mux);
vTaskDelay(( DELAY_TIME_BETWEEN_ITEMS_MS * ( task_idx + 1 ) ) / portTICK_RATE_MS);
}
}
void app_main()
{
print_mux = xSemaphoreCreateMutex();
i2c_slave_init();
i2c_master_init();
xTaskCreate(i2c_test_task, "i2c_test_task_0", 1024 * 2, (void* ) 0, 10, NULL);
xTaskCreate(i2c_test_task, "i2c_test_task_1", 1024 * 2, (void* ) 1, 10, NULL);
}

Some files were not shown because too many files have changed in this diff Show More