RISCV-ULP: Add DS18B20 1wire RISCV-ULP example

pull/7307/head
Marius Vikhammer 2021-06-23 14:54:36 +08:00
rodzic 67743ac444
commit 386739595f
38 zmienionych plików z 369 dodań i 25 usunięć

Wyświetl plik

@ -32,12 +32,14 @@
esp_err_t ulp_riscv_run(void)
{
/* Reset COCPU when power on. */
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_CLK_FO);
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT_RESET_EN);
esp_rom_delay_us(20);
CLEAR_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_CLK_FO);
CLEAR_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT_RESET_EN);
/* The coprocessor cpu trap signal doesnt have a stable reset value,
force ULP-RISC-V clock on to stop RTC_COCPU_TRAP_TRIG_EN from waking the CPU*/
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_CLK_FO);
/* Disable ULP timer */
CLEAR_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
/* wait for at least 1 RTC_SLOW_CLK cycle */

Wyświetl plik

@ -20,6 +20,8 @@ extern "C" {
#include "ulp_riscv/ulp_riscv.h"
#include "soc/rtc_io_reg.h"
#include "soc/sens_reg.h"
typedef enum {
GPIO_NUM_0 = 0, /*!< GPIO0, input and output */
@ -51,38 +53,39 @@ typedef enum {
RTCIO_MODE_OUTPUT_OD = 1,
} rtc_io_out_mode_t;
static inline void example_ulp_gpio_init(gpio_num_t gpio_num)
static inline void ulp_riscv_gpio_init(gpio_num_t gpio_num)
{
SET_PERI_REG_MASK(SENS_SAR_IO_MUX_CONF_REG, SENS_IOMUX_CLK_GATE_EN_M);
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num*4, RTC_IO_TOUCH_PAD0_MUX_SEL);
REG_SET_FIELD(RTC_IO_TOUCH_PAD0_REG + gpio_num*4, RTC_IO_TOUCH_PAD0_FUN_SEL, 0);
}
static inline void example_ulp_gpio_deinit(gpio_num_t gpio_num)
static inline void ulp_riscv_gpio_deinit(gpio_num_t gpio_num)
{
CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num*4, RTC_IO_TOUCH_PAD0_MUX_SEL);
}
static inline void example_ulp_gpio_output_enable(gpio_num_t gpio_num)
static inline void ulp_riscv_gpio_output_enable(gpio_num_t gpio_num)
{
REG_SET_FIELD(RTC_GPIO_ENABLE_W1TS_REG, RTC_GPIO_ENABLE_W1TS, BIT(gpio_num));
}
static inline void example_ulp_gpio_output_disable(gpio_num_t gpio_num)
static inline void ulp_riscv_gpio_output_disable(gpio_num_t gpio_num)
{
REG_SET_FIELD(RTC_GPIO_ENABLE_W1TC_REG, RTC_GPIO_ENABLE_W1TC, BIT(gpio_num));
}
static inline void example_ulp_gpio_input_enable(gpio_num_t gpio_num)
static inline void ulp_riscv_gpio_input_enable(gpio_num_t gpio_num)
{
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num*4, RTC_IO_TOUCH_PAD0_FUN_IE);
}
static inline void example_ulp_gpio_input_disable(gpio_num_t gpio_num)
static inline void ulp_riscv_gpio_input_disable(gpio_num_t gpio_num)
{
CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num*4, RTC_IO_TOUCH_PAD0_FUN_IE);
}
static inline void example_ulp_gpio_output_level(gpio_num_t gpio_num, uint8_t level)
static inline void ulp_riscv_gpio_output_level(gpio_num_t gpio_num, uint8_t level)
{
if (level) {
REG_SET_FIELD(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS, BIT(gpio_num));
@ -91,32 +94,32 @@ static inline void example_ulp_gpio_output_level(gpio_num_t gpio_num, uint8_t le
}
}
static inline uint8_t example_ulp_gpio_get_level(gpio_num_t gpio_num)
static inline uint8_t ulp_riscv_gpio_get_level(gpio_num_t gpio_num)
{
return (uint8_t)((REG_GET_FIELD(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT) & BIT(gpio_num)) ? 1 : 0);
}
static inline void example_ulp_gpio_set_output_mode(gpio_num_t gpio_num, rtc_io_out_mode_t mode)
static inline void ulp_riscv_gpio_set_output_mode(gpio_num_t gpio_num, rtc_io_out_mode_t mode)
{
REG_SET_FIELD(RTC_IO_TOUCH_PAD0_REG + gpio_num*4, RTC_IO_TOUCH_PAD0_DRV, mode);
}
static inline void example_ulp_gpio_pullup(gpio_num_t gpio_num)
static inline void ulp_riscv_gpio_pullup(gpio_num_t gpio_num)
{
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num*4, RTC_IO_TOUCH_PAD0_RUE);
}
static inline void example_ulp_gpio_pullup_disable(gpio_num_t gpio_num)
static inline void ulp_riscv_gpio_pullup_disable(gpio_num_t gpio_num)
{
CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num*4, RTC_IO_TOUCH_PAD0_RUE);
}
static inline void example_ulp_gpio_pulldown(gpio_num_t gpio_num)
static inline void ulp_riscv_gpio_pulldown(gpio_num_t gpio_num)
{
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num*4, RTC_IO_TOUCH_PAD0_RDE);
}
static inline void example_ulp_gpio_pulldown_disable(gpio_num_t gpio_num)
static inline void ulp_riscv_gpio_pulldown_disable(gpio_num_t gpio_num)
{
CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num*4, RTC_IO_TOUCH_PAD0_RDE);
}

Wyświetl plik

@ -58,6 +58,24 @@ void ulp_riscv_rescue_from_monitor(void);
*/
void __attribute__((noreturn)) ulp_riscv_shutdown(void);
#define ULP_RISCV_GET_CCOUNT() ({ int __ccount; \
asm volatile("rdcycle %0;" : "=r"(__ccount)); \
__ccount; })
/* These are only approximate default numbers, the default frequency
of the 8M oscillator is 8.5MHz +/- 5%, at the default DCAP setting
*/
#define ULP_RISCV_CYCLES_PER_US 8.5
#define ULP_RISCV_CYCLES_PER_MS ULP_RISCV_CYCLES_PER_US*1000
/**
* @brief Makes the co-processor busy wait for a certain number of cycles
*
* @param cycles Number of cycles to busy wait
*/
void ulp_riscv_delay_cycles(uint32_t cycles);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -39,3 +39,12 @@ void ulp_riscv_shutdown(void)
while(1);
}
void ulp_riscv_delay_cycles(uint32_t cycles)
{
uint32_t start = ULP_RISCV_GET_CCOUNT();
while ((ULP_RISCV_GET_CCOUNT() - start) < cycles) {
/* Wait */
}
}

Wyświetl plik

@ -10,7 +10,7 @@ from tiny_test_fw import Utility
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32'])
def test_examples_ulp(env, extra_data):
dut = env.get_dut('ulp', 'examples/system/ulp')
dut = env.get_dut('ulp', 'examples/system/ulp_fsm/ulp')
dut.start_app()
dut.expect_all('Not ULP wakeup, initializing ULP',

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 38 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 38 KiB

Wyświetl plik

@ -9,7 +9,7 @@ from tiny_test_fw import Utility
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32'])
def test_examples_ulp_adc(env, extra_data):
dut = env.get_dut('ulp_adc', 'examples/system/ulp_adc')
dut = env.get_dut('ulp_adc', 'examples/system/ulp_fsm/ulp_adc')
dut.start_app()
dut.expect_all('Not ULP wakeup',

Wyświetl plik

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ulp-riscv-ds18b20-example)

Wyświetl plik

@ -0,0 +1,42 @@
| Supported Targets | ESP32-S2 |
| ----------------- | -------- |
# ULP-RISC-V DS18B20 Temperature Sensor OneWire Communication
This example demonstrates how to program the ULP-RISC-V co-processor to read temperature from a [DS18B20](https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf) temperature sensor over 1-Wire.
When the measurement exceeds the limit set(32.5 degrees) the co-processor will wake up the main CPU from deep-sleep and the main CPU will print the temperature measurement.
### Hardware Required
* A development board with a SOC which has a RISC-V ULP coprocessor (e.g., ESP32-S2 Saola)
* A USB cable for power supply and programming
* A DS18B20 temperature sensor
Example connection :
| ESP Dev-kit | DS18B20 |
| ------------ | ------- |
| GPIO4 | DQ |
| VCC 3.3V | VDD |
| GND | GND |
## Example output
```
Not a ULP wakeup, initializing it!
Entering in deep sleep
...
ULP-RISC-V woke up the main CPU, temperature is above set limit!
ULP-RISC-V read temperature is 32.562500
Entering in deep sleep
...
ULP-RISC-V woke up the main CPU, temperature is above set limit!
ULP-RISC-V read temperature is 33.000000
Entering in deep sleep
```

Wyświetl plik

@ -0,0 +1,27 @@
# Set usual component variables
set(COMPONENT_SRCS "ulp_riscv_ds18b20_example_main.c")
set(COMPONENT_ADD_INCLUDEDIRS "")
set(COMPONENT_REQUIRES soc nvs_flash ulp driver)
register_component()
#
# ULP support additions to component CMakeLists.txt.
#
# 1. The ULP app name must be unique (if multiple components use ULP).
set(ulp_app_name ulp_${COMPONENT_NAME})
#
# 2. Specify all C and Assembly source files.
# Files should be placed into a separate directory (in this case, ulp/),
# which should not be added to COMPONENT_SRCS.
set(ulp_riscv_sources "ulp/main.c")
#
# 3. List all the component source files which include automatically
# generated ULP export file, ${ulp_app_name}.h:
set(ulp_exp_dep_srcs "ulp_riscv_ds18b20_example_main.c")
#
# 4. Call function to build ULP binary and embed in project using the argument
# values above.
ulp_embed_binary(${ulp_app_name} "${ulp_riscv_sources}" "${ulp_exp_dep_srcs}")

Wyświetl plik

@ -0,0 +1,156 @@
/* ULP-RISC-V example
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.
This code runs on ULP-RISC-V coprocessor
*/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include "ulp_riscv/ulp_riscv.h"
#include "ulp_riscv/ulp_riscv_utils.h"
#include "ulp_riscv/ulp_riscv_gpio.h"
#define EXAMPLE_1WIRE_GPIO GPIO_NUM_4
#define WAKEUP_TEMP_C 32.5
#define TEMP_ALARM_LIMIT ( (int)(WAKEUP_TEMP_C*16) )
typedef enum {
SENSOR_CONVERSION_INIT,
SENSOR_CONVERSION_READ,
} sensor_state_t;
sensor_state_t state = SENSOR_CONVERSION_INIT;
int32_t temp_reg_val = INT32_MIN;
static void ds18b20_write_bit(bool bit)
{
ulp_riscv_gpio_output_level(EXAMPLE_1WIRE_GPIO, 0);
if (bit) {
/* Must pull high within 15 us, without delay this takes 5 us */
ulp_riscv_gpio_output_level(EXAMPLE_1WIRE_GPIO, 1);
}
/* Write slot duration at least 60 us */
ulp_riscv_delay_cycles(60 * ULP_RISCV_CYCLES_PER_US);
ulp_riscv_gpio_output_level(EXAMPLE_1WIRE_GPIO, 1);
}
static bool ds18b20_read_bit(void)
{
bool bit;
/* Pull low minimum 1 us */
ulp_riscv_gpio_output_level(EXAMPLE_1WIRE_GPIO, 0);
ulp_riscv_gpio_output_level(EXAMPLE_1WIRE_GPIO, 1);
/* Must sample within 15 us of the failing edge */
ulp_riscv_delay_cycles(5 * ULP_RISCV_CYCLES_PER_US);
bit = ulp_riscv_gpio_get_level(EXAMPLE_1WIRE_GPIO);
/* Read slot duration at least 60 us */
ulp_riscv_delay_cycles(55 * ULP_RISCV_CYCLES_PER_US);
return bit;
}
static void ds18b20_write_byte(uint8_t data)
{
for (int i = 0; i < 8; i++) {
ds18b20_write_bit((data >> i) & 0x1);
}
}
static uint8_t ds18b20_read_byte(void)
{
uint8_t data = 0;
for (int i = 0; i < 8; i++) {
data |= ds18b20_read_bit() << i;
}
return data;
}
bool ds18b20_reset_pulse(void)
{
bool presence_pulse;
/* min 480 us reset pulse + 480 us reply time is specified by datasheet */
ulp_riscv_gpio_output_level(EXAMPLE_1WIRE_GPIO, 0);
ulp_riscv_delay_cycles(480 * ULP_RISCV_CYCLES_PER_US);
ulp_riscv_gpio_output_level(EXAMPLE_1WIRE_GPIO, 1);
/* Wait for ds18b20 to pull low before sampling */
ulp_riscv_delay_cycles(60 * ULP_RISCV_CYCLES_PER_US);
presence_pulse = ulp_riscv_gpio_get_level(EXAMPLE_1WIRE_GPIO) == 0;
ulp_riscv_delay_cycles(420 * ULP_RISCV_CYCLES_PER_US);
return presence_pulse;
}
int main (void)
{
uint8_t temp_high_byte;
uint8_t temp_low_byte;
/* Setup GPIO used for 1wire */
ulp_riscv_gpio_init(EXAMPLE_1WIRE_GPIO);
ulp_riscv_gpio_input_enable(EXAMPLE_1WIRE_GPIO);
ulp_riscv_gpio_output_enable(EXAMPLE_1WIRE_GPIO);
ulp_riscv_gpio_set_output_mode(EXAMPLE_1WIRE_GPIO, RTCIO_MODE_OUTPUT_OD);
ulp_riscv_gpio_pullup(EXAMPLE_1WIRE_GPIO);
ulp_riscv_gpio_pulldown_disable(EXAMPLE_1WIRE_GPIO);
switch (state) {
case SENSOR_CONVERSION_INIT:
if (!ds18b20_reset_pulse()) {
temp_reg_val = INT32_MIN;
break;
}
/* Start conversion */
ds18b20_write_byte(0xCC);
ds18b20_write_byte(0x44);
/* shutdown and wait for next period (750ms) where the data is ready for reading */
state = SENSOR_CONVERSION_READ;
break;
case SENSOR_CONVERSION_READ:
if (!ds18b20_reset_pulse()) {
temp_reg_val = INT32_MIN;
state = SENSOR_CONVERSION_INIT;
break;
}
/* Read scratchpad */
ds18b20_write_byte(0xCC);
ds18b20_write_byte(0xBE);
temp_low_byte = ds18b20_read_byte();
temp_high_byte = ds18b20_read_byte();
temp_reg_val = temp_high_byte << 8;
temp_reg_val |= temp_low_byte;
state = SENSOR_CONVERSION_INIT;
/* Wakes up the main CPU if the temperature exceeds the limit */
if (temp_reg_val > TEMP_ALARM_LIMIT) {
ulp_riscv_wakeup_main_processor();
}
break;
}
/* ulp_riscv_shutdown() is called automatically when main exits,
main will be executed again at the next timeout period,
according to ulp_set_wakeup_period()
*/
return 0;
}

Wyświetl plik

@ -0,0 +1,72 @@
/* ULP riscv example
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 "esp_sleep.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/sens_reg.h"
#include "soc/rtc_periph.h"
#include "hal/rtc_io_ll.h"
#include "driver/gpio.h"
#include "driver/rtc_io.h"
#include "esp32s2/ulp.h"
#include "esp32s2/ulp_riscv.h"
#include "ulp_main.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
/* We alternate between start conversion and read result every other ULP wakeup,
Conversion time is 750 ms for 12 bit resolution
*/
#define WAKEUP_PERIOD_US (750000)
extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start");
extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end");
static void init_ulp_program(void);
void app_main(void)
{
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
/* not a wakeup from ULP, load the firmware */
if (cause != ESP_SLEEP_WAKEUP_ULP) {
printf("Not a ULP-RISC-V wakeup (cause = %d), initializing it! \n", cause);
init_ulp_program();
}
/* ULP Risc-V read and detected a temperature above the limit */
if (cause == ESP_SLEEP_WAKEUP_ULP) {
printf("ULP-RISC-V woke up the main CPU, temperature is above set limit! \n");
printf("ULP-RISC-V read temperature is %f\n", ulp_temp_reg_val / 16.0);
}
/* Go back to sleep, only the ULP Risc-V will run */
printf("Entering in deep sleep\n\n");
/* Small delay to ensure the messages are printed */
vTaskDelay(100);
ESP_ERROR_CHECK( esp_sleep_enable_ulp_wakeup());
esp_deep_sleep_start();
}
static void init_ulp_program(void)
{
esp_err_t err = ulp_riscv_load_binary(ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start));
ESP_ERROR_CHECK(err);
/* The first argument is the period index, which is not used by the ULP-RISC-V timer
* The second argument is the period in microseconds, which gives a wakeup time period of: 750ms
*/
ulp_set_wakeup_period(0, WAKEUP_PERIOD_US);
/* Start the program */
err = ulp_riscv_run();
ESP_ERROR_CHECK(err);
}

Wyświetl plik

@ -9,7 +9,7 @@ from tiny_test_fw import DUT
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32s2'])
def test_examples_ulp_riscv(env, extra_data): # type: (tiny_test_fw.Env.Env, None) -> None # pylint: disable=unused-argument
dut = env.get_dut('ulp_riscv', 'examples/system/ulp_riscv')
dut = env.get_dut('ulp_riscv', 'examples/system/ulp_riscv/gpio')
dut.start_app()
dut.expect_all('Not a ULP-RISC-V wakeup, initializing it!',

Wyświetl plik

@ -14,7 +14,7 @@
#include <stdbool.h>
#include "ulp_riscv/ulp_riscv.h"
#include "ulp_riscv/ulp_riscv_utils.h"
#include "example_ulp_gpio.h"
#include "ulp_riscv/ulp_riscv_gpio.h"
static bool gpio_level = false;
@ -23,11 +23,11 @@ bool gpio_level_previous = false;
int main (void)
{
gpio_level = (bool)example_ulp_gpio_get_level(GPIO_NUM_0);
gpio_level = (bool)ulp_riscv_gpio_get_level(GPIO_NUM_0);
gpio_level_previous = gpio_level;
while(1) {
gpio_level = (bool)example_ulp_gpio_get_level(GPIO_NUM_0);
gpio_level = (bool)ulp_riscv_gpio_get_level(GPIO_NUM_0);
/* Wakes up the main CPU if pin changed its state */
if(gpio_level != gpio_level_previous) {
@ -35,7 +35,6 @@ int main (void)
ulp_riscv_wakeup_main_processor();
break;
}
}
/* ulp_riscv_shutdown() is called automatically when main exits */
return 0;

Wyświetl plik

@ -1,4 +1,4 @@
/* ULP riscv example
/* ULP riscv DS18B20 1wire temperature sensor example
This example code is in the Public Domain (or CC0 licensed, at your option.)

Wyświetl plik

@ -0,0 +1,10 @@
CONFIG_IDF_TARGET="esp32s2"
# Enable ULP
CONFIG_ESP32S2_ULP_COPROC_ENABLED=y
CONFIG_ESP32S2_ULP_COPROC_RISCV=y
CONFIG_ESP32S2_ULP_COPROC_RESERVE_MEM=4096
# Set log level to Warning to produce clean output
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
CONFIG_BOOTLOADER_LOG_LEVEL=2
CONFIG_LOG_DEFAULT_LEVEL_WARN=y
CONFIG_LOG_DEFAULT_LEVEL=2

Wyświetl plik

@ -144,8 +144,8 @@ examples/system/startup_time/example_test.py
examples/system/sysview_tracing/example_test.py
examples/system/sysview_tracing_heap_log/example_test.py
examples/system/task_watchdog/example_test.py
examples/system/ulp/example_test.py
examples/system/ulp_adc/example_test.py
examples/system/ulp_fsm/ulp/example_test.py
examples/system/ulp_fsm/ulp_adc/example_test.py
examples/system/unit_test/example_test.py
examples/wifi/iperf/iperf_test.py
tools/ble/lib_ble_client.py