Giter Site home page Giter Site logo

elcritch / nesper Goto Github PK

View Code? Open in Web Editor NEW
182.0 11.0 16.0 2.82 MB

Program the ESP32 with Nim! Wrappers around ESP-IDF API's.

License: Apache License 2.0

Nim 21.78% C 77.76% CMake 0.22% Makefile 0.10% Python 0.02% Shell 0.12% Dockerfile 0.01%
nim nesper freertos esp-idf esp32

nesper's Introduction

Nesper

Program the ESP32 using Nim! This library builds on the esp-idf. Nim now has support for FreeRTOS & LwIP. Combined with the new ARC garbage collector makes Nim an excellent language for programming the ESP32.

See Releases for updates.

Status

This project is fairly stable and even being used in shipping hardware project. The documentation is rough and primarily only includes this README. As such, it may still require understanding the underlying ESP-IDF SDK for various use cases. However, it is useable and several people unfamiliar with ESP-IDF and embedded programming have added wrappers for esp-idf modules.

Note: It's recommended to use the ESP-IDF.py v4.0 branch (as of 2020-11-24). Branch v4.1 has multiple serious bugs in I2C.

General Usage

  1. Install ESP-IDF
    • TLDR: git clone -b release/v4.0 --recursive https://github.com/espressif/esp-idf.git
    • esp-idf version 4.0 is recommended for now since its more stable
    • esp-idf version can be set using the defines: -d:ESP_IDF_V4_0 or -d:ESP_IDF_V4_1
  2. Install Nim 1.4+
  3. Use Nimble to install Nesper (nimble install https://github.com/elcritch/nesper or for the devel branch nimble install 'https://github.com/elcritch/nesper@#devel' )
  4. Create a new Nimble project nimble init --git esp32_nim_example
  5. In the new project directory edit the Nimble file and add the lines:
requires "nesper >= 0.6.1"
# includes nimble tasks for building Nim esp-idf projects
include nesper/build_utils/tasks
  • Make sure not to include a bin option like bin = @["src/esp32_nim_example"] as this will override the nimble esp_build and result in a broken idf.py build.
  1. Run nimble esp_setup to setup the correct files for building an esp32/esp-idf project

Compiling and Building

  1. Run nimble esp_build to build the esp-idf project
  2. Flash and monitor the esp32 board using: idf.py -p </dev/ttyUSB0> flash monitor

Notes:

  • Running nimble esp_build will both compile the Nim code and then build the esp-idf project
  • During development it's often handy just to run nimble esp_compile to check your Nim code works
  • Sometimes the Nim build cache gets out of sync, use nimble esp_build --clean to force a full Nim recompile
  • Sometimes the esp-idf build cache gets out of sync, use nimble esp_build --dist-clean to force a full Nim recompile

Example Code

This code shows a short example of setting up an http server to toggle a GPIO pin. It uses the default async HTTP server in Nim's standard library. It still requires the code to initialize the ESP32 and WiFi or ethernet.

import asynchttpserver, asyncdispatch, net
import nesper, nesper/consts, nesper/general, nesper/gpios

const
  MY_PIN_A* = gpio_num_t(4)
  MY_PIN_B* = gpio_num_t(5)

var 
  level = false
  
proc config_pins() =
    MOTOR1_PIN.setLevel(true)

proc http_cb*(req: Request) {.async.} =
    level = not level 
    echo "toggle my pin to: #", $level
    MY_PIN_A.setLevel(level)
    await req.respond(Http200, "Toggle MY_PIN_A: " & $level)

proc run_http_server*() {.exportc.} =
    echo "Configure pins"
    {MY_PIN_A, MY_PIN_B}.configure(MODE_OUTPUT) 
    MY_PIN_A.setLevel(lastLevel)
    
    echo "Starting http server on port 8181"
    var server = newAsyncHttpServer()
    waitFor server.serve(Port(8181), http_cb)

Why

TLDR; Real reason? It's a bit of fun in a sometimes tricky field.

I generally dislike programming C/C++ (despite C's elegance in the small). When you just want a hash table in C it's tedious and error prone. C++ is about 5 different languages and I have to idea how to use half of them anymore. Rust doesn't work on half of the boards I want to program. MicroPython? ... Nope - I need speed and efficiency.

Library

The library is currently a collection of random ESP-IDF libraries that I import using c2nim as needed. Sometimes there's a bit extra wrapping to provide a nicer Nim API.

Caveat: these features are tested as they're used for my use case. However, both Nim and the esp-idf seem designed well enough that they mostly "just work". PR's are welcome!

Supported ESP-IDF drivers with Nim'ified interfaces:

  • Nim stdandard library support for most basic POSIX network API's!
  • Most of the basic FreeRTOS.h header
  • NVS Flash
  • UART
  • SPI (don't mix half-duplex & duplex devices)
  • I2C

Other things:

  • Nim standard library wrapping of FreeRTOS semaphore's, mutexes, etc
    • include pthread in your CMakeLists.txt file and use Nim's POSIX lock API's
  • Nim support for xqueue and other "thread safe" data structures
  • Nim standard library support for FreeRTOS tasks using thread api's
    • include pthread in your CMakeLists.txt file and use Nim's POSIX Pthread API's

Things I'm not planning on (PR's welcome!)

  • I2S
  • PWM
  • LCDs
  • Built-in ADC

Manual Setup

This is the more manual setup approach:

  1. It's recommend to copy nesper/esp-idf-examples/simplewifi example project initially, to get the proper build steps.
    • git clone https://github.com/elcritch/nesper
    • cp -Rv nesper/esp-idf-examples/simplewifi/ ./nesper-simplewifi
    • cd ./nesper-simplewifi/
    • make build (also make esp_v40 or make esp_v41 )
  2. Nesper wrapper API names generally match the C names directly, usually in snake case
  • FreeRTOS functions usually are camel case and start with an x, e.g. xTaskDelay
  • These api's are found under nesper/esp/* or nesper/esp/net/*, e.g. nesper/esp/nvs
  1. Nesper Nim friendly api, usually in camel case
  • These api's are found under nesper/*, e.g. nesper/nvs

Example Async server on a ESP32-CAM (or other Esp32 Wifi board)

See SimpleWifi Example

The async code really is simple Nim code:

import asynchttpserver, asyncdispatch, net

var count = 0

proc cb*(req: Request) {.async.} =
    inc count
    echo "req #", count
    await req.respond(Http200, "Hello World from nim on ESP32\n")
    # GC_fullCollect()

proc run_http_server*() {.exportc.} =
    echo "starting http server on port 8181"
    var server = newAsyncHttpServer()

    waitFor server.serve(Port(8181), cb)

when isMainModule:
    echo "running server"
    run_http_server()

Nim-ified ESP32 APIs

GPIOs

import nesper, nesper/consts, nesper/general, nesper/gpios

const
  MOTOR1_PIN* = gpio_num_t(4)
  MOTOR2_PIN* = gpio_num_t(5)

proc config_pins() =
  # Inputs pins use Nim's set `{}` notation
  configure({MOTOR1_PIN, MOTOR2_PIN}, GPIO_MODE_INPUT)
  # or method call style:
  {MOTOR1_PIN, MOTOR2_PIN}.configure(MODE_INPUT)
  
  MOTOR1_PIN.setLevel(true)
  MOTOR2_PIN.setLevel(false) 

SPIs

import nesper, nesper/consts, nesper/general, nesper/spis

proc cs_adc_pre(trans: ptr spi_transaction_t) {.cdecl.} = ... 
proc cs_unselect(trans: ptr spi_transaction_t) {.cdecl.} = ...

proc config_spis() = 
  # Setup SPI example using custom Chip select pins using pre/post callbacks 
  let
    std_hz = 1_000_000.cint()
    fast_hz = 8_000_000.cint()
    
  var BUS1 = HSPI.newSpiBus(
        mosi = gpio_num_t(32),
        sclk = gpio_num_t(33),
        miso = gpio_num_t(34),
        dma_channel=0,
        flags={MASTER})

  logi(TAG, "cfg_spi: bus1: %s", repr(BUS1))

  var ADC_SPI = BUS1.addDevice(commandlen = bits(8),
                               addresslen = bits(0),
                               mode = 0,
                               cs_io = gpio_num_t(-1),
                               clock_speed_hz = fast_hz, 
                               queue_size = 1,
                               pre_cb=cs_adc_pre,
                               post_cb=cs_unselect,
                               flags={HALFDUPLEX})

Later these can be used like:

const 
  ADC_READ_MULTI_CMD =  0x80
  ADC_REG_CONFIG0 = 0x03

proc read_regs*(reg: byte, n: range[1..16]): SpiTrans =
  let read_cmd = reg or ADC_READ_MULTI_CMD # does bitwise or
  return ADC_SPI.readTrans(cmd=read_cmd, rxlength=bytes(n), )

proc adc_read_config*(): seq[byte] =
  var trn = read_regs(ADC_REG_CONFIG0, 2)
  trn.transmit() # preforms SPI transaction using transaction queue
  result = trn.getData()

See more in the test SPI Test or the read the wrapper (probably best docs for now): spis.nim.

Wear levelling / Virtual FAT filesystem

import nesper, nesper/esp_vfs_fat

var
  base_path : cstring = "/spiflash"
  s_wl_handle : wl_handle_t = WL_INVALID_HANDLE

mount_config = esp_vfs_fat_mount_config_t(format_if_mount_failed: true,
                                          max_files: 10, allocation_unit_size: 4096)
err = esp_vfs_fat_spiflash_mount(base_path, "storage", mount_config.addr, s_wl_handle.addr)

if err != ESP_OK:
  echo "Failed to mount FATFS."
else:
  echo "FATFS mounted successfully!"

writeFile("/spiflash/hello.txt", "Hello world!")
echo readFile("/spiflash/hello.txt") # Hello world!

Notice: file extension of files on FAT filesystem is limited to maximum of 3 characters.

Why Nim for Embedded?

Nim is a flexible language which compiles to a variety of backend "host" languages, including C and C++. Like many hosted languages, it has excellent facilities to interact with the host language natively. In the embedded world this means full compatability with pre-existing libraries and toolchains, which are often complex and difficult to interface with from an "external language" like Rust or even C++. They often also require oddball compilers, ruling out LLVM based lanugages for many projects (including the ESP32 which defaults to a variant of GCC).

Nim has a few nice features for embedded work:

Language:

  • High level language and semantics with low level bit fiddling and pointers
  • Flexible garbage collector or manual memory management
    • ARC GC allows using native-C debuggers, meaning any embedded debuggers should work too!
    • ARG GC doesn't use locks, and utilizies move semantics -- it's fast
  • Simple FFI's around to import and/or wrap C/C++ libraries
  • Async/Event support
  • Real hygenic language macros, and collections with generics!
  • Very flexible and hackable standard library!

Libraries:

  • Simplified network wrappers around native sockets (i.e. use select w/o a PhD)
  • Sane standard library, including JSON, datetime, crypto, ...
    • Efficient compiler that eliminates un-needed code (i.e. json support using a few extra kB's)
    • Package library manager

Compiler:

  • Fast compilation, generated C compiles fast
  • Deterministic exception handling using a non-malloc friendly goto technique
  • Object-oriented like programming that's not based on vtables

There are a few cons of Nim:

  • Lack of documentation for many parts of the standard library
  • Understanding the differences between stack/heap based objects is a bit tricky
  • Compiler options are often incompatible and can require some experimentation
  • Small community (e.g. lack of some libraries)
  • You likely won't get to use it at XYZ Megacorp
  • It will require some pioneering!

nesper's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nesper's Issues

Test and validate new release

There are a number of fixes / modifications on devel branch. They need to be tested all together and a new release created.

esp_setup fails to execute?

Hey there, trying to set this up!

PS C:\Users\JoshGirvin\Code\firmware-nesper> nimble esp_setup
  Executing task esp_setup in C:\Users\JoshGirvin\Code\firmware-nesper\esp32_nim_example.nimble

[Nesper ESP] setting up project:
...create project source directory
...writing cmake lists
io.nim(853)              readFile
Error: unhandled exception: cannot open: C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0
\nesper\build_utils\templates\CMakeLists.txt [IOError]
     Error: Exception raised during nimble script execution

This is what I get following the process outlined in the README. Any ideas what could be causing it?

PS C:\Users\JoshGirvin\Code\firmware-nesper> ls C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0


    Directory: C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        18/02/2022   2:34 PM                nesper
-a----        18/02/2022   2:34 PM            537 nesper.nim
-a----        18/02/2022   2:34 PM           1661 nesper.nimble
-a----        18/02/2022   2:34 PM           3922 nimblemeta.json

Can't read from I2C

I'm trying to use a peripheral from Adafruit which communicates over I2C. The same setup works fine with their Arduino library. I copied the protocol from there, and I can't see anything wrong with my implementation, but it doesn't work via Nesper ๐Ÿคทโ€โ™‚๏ธ I've tried messing with the clock speed, different pins, different pullups, etc. I can tell there's some communication happening, because any other address hangs the system (wish I had an oscilloscope), but all I get is 0xFF back for every byte for every register I try.

Any ideas? Am I doing something wrong?

import nesper/timers
import nesper/i2cs
import nesper
#

const
  TAG*: cstring = "input"
  SCL_PIN = gpio_num_t(22)
  SDA_PIN = gpio_num_t(23)
  SEESAW_ADC_BASE = 0x09'u8
  SEESAW_GPIO_BASE = 0x01'u8
  SEESAW_ADC_CHANNEL_OFFSET = 0x07'u8
  SEESAW_GPIO_DIRSET_BULK = 0x02'u8
  SEESAW_GPIO_DIRCLR_BULK = 0x03'u8
  SEESAW_GPIO_BULK = 0x04'u8
  SEESAW_GPIO_BULK_SET = 0x05'u8
  SEESAW_GPIO_BULK_CLR = 0x06'u8
  SEESAW_GPIO_BULK_TOGGLE = 0x07'u8
  SEESAW_GPIO_INTENSET = 0x08'u8
  SEESAW_GPIO_INTENCLR = 0x09'u8
  SEESAW_GPIO_INTFLAG = 0x0A'u8
  SEESAW_GPIO_PULLENSET = 0x0B'u8
  SEESAW_GPIO_PULLENCLR = 0x0C'u8
  BUTTON_RIGHT= 6
  BUTTON_DOWN = 7
  BUTTON_LEFT = 9
  BUTTON_UP   = 10
  BUTTON_SEL  = 14
  button_mask: uint32 = (1 shl BUTTON_RIGHT) or (1 shl BUTTON_DOWN) or 
                  (1 shl BUTTON_LEFT) or (1 shl BUTTON_UP) or (1 shl BUTTON_SEL)

let port1 = newI2CMaster(port = I2C_NUM_0,
                          sda_io_num = SDA_PIN, ## !< GPIO number for I2C sda signal
                          scl_io_num = SCL_PIN, ## !< GPIO number for I2C scl signal
                          clk_speed = 100_000.Hertz,
                          sda_pullup_en = false, ## !< Internal GPIO pull mode for I2C sda signal
                          scl_pullup_en = false, ## !< Internal GPIO pull mode for I2C scl signal
                          intr_alloc_flags = {})


proc seesawWrite(bs: seq[uint8]) =
  var cmd = port1.newCmd()
  cmd.start()
  cmd.writeTo(0x49)
  for b in bs:
    cmd.writeByte(b)
  cmd.stop()
  port1.submit(cmd, 10.Millis)

proc seesawRead(bs: seq[uint8], size: uint): seq[uint8] =
  result = newSeq[uint8](size)
  seesawWrite(bs)
  delayMillis(1)
  var readCmd = port1.newCmd()
  readCmd.start()
  readCmd.readFrom(0x49)
  readCmd.read(result, ACK)
  readCmd.stop()
  port1.submit(readCmd, 10.Millis)

proc initInput*() = 
  let maskcmd = @[uint8(button_mask shr 24), uint8(button_mask shr 16),
                   uint8(button_mask shr 8), uint8(button_mask and 0xFF)]
  seesawWrite(@[SEESAW_GPIO_BASE, SEESAW_GPIO_DIRCLR_BULK] & maskCmd)
  seesawWrite(@[SEESAW_GPIO_BASE, SEESAW_GPIO_PULLENSET] & maskCmd)
  seesawWrite(@[SEESAW_GPIO_BASE, SEESAW_GPIO_BULK_SET] & maskCmd)
  seesawWrite(@[SEESAW_GPIO_BASE, SEESAW_GPIO_INTENSET] & maskCmd)

proc printButtons*() =
  echo(seesawRead(@[SEESAW_GPIO_BASE, SEESAW_GPIO_BULK], 8))
  echo(seesawRead(@[SEESAW_ADC_BASE, SEESAW_ADC_CHANNEL_OFFSET], 2))

error: size of array 'NIM_STATIC_ASSERT_AUX' is negative

Hi, I'm trying to build the example, and I've actually gotten quite far, 807 out of 812 steps in ninja :). However, there is an error now:

[807/821] Building C object 'esp-idf/main/CMakeFiles/__idf_main.dir/nimcache/@mesp32_nim_test.nim.c.obj'
FAILED: esp-idf/main/CMakeFiles/__idf_main.dir/nimcache/@mesp32_nim_test.nim.c.obj 
/home/psirus/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/xtensa-esp32-elf-gcc -DMBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\" -Iconfig -I/home/psirus/Code/C/esp-idf/components/newlib/platform_include -I/home/psirus/Code/C/esp-idf/components/freertos/include -I/home/psirus/Code/C/esp-idf/components/heap/include -I/home/psirus/Code/C/esp-idf/components/log/include -I/home/psirus/Code/C/esp-idf/components/soc/esp32/include -I/home/psirus/Code/C/esp-idf/components/soc/include -I/home/psirus/Code/C/esp-idf/components/esp_rom/include -I/home/psirus/Code/C/esp-idf/components/esp_common/include -I/home/psirus/Code/C/esp-idf/components/xtensa/include -I/home/psirus/Code/C/esp-idf/components/xtensa/esp32/include -I/home/psirus/Code/C/esp-idf/components/esp32/include -I/home/psirus/Code/C/esp-idf/components/driver/include -I/home/psirus/Code/C/esp-idf/components/esp_ringbuf/include -I/home/psirus/Code/C/esp-idf/components/esp_event/include -I/home/psirus/Code/C/esp-idf/components/tcpip_adapter/include -I/home/psirus/Code/C/esp-idf/components/lwip/include/apps -I/home/psirus/Code/C/esp-idf/components/lwip/include/apps/sntp -I/home/psirus/Code/C/esp-idf/components/lwip/lwip/src/include -I/home/psirus/Code/C/esp-idf/components/lwip/port/esp32/include -I/home/psirus/Code/C/esp-idf/components/lwip/port/esp32/include/arch -I/home/psirus/Code/C/esp-idf/components/lwip/port/esp32/tcp_isn -I/home/psirus/Code/C/esp-idf/components/vfs/include -I/home/psirus/Code/C/esp-idf/components/esp_wifi/include -I/home/psirus/Code/C/esp-idf/components/esp_wifi/esp32/include -I/home/psirus/Code/C/esp-idf/components/esp_eth/include -I/home/psirus/Code/C/esp-idf/components/efuse/include -I/home/psirus/Code/C/esp-idf/components/efuse/esp32/include -I/home/psirus/Code/C/esp-idf/components/app_trace/include -I/home/psirus/Code/C/esp-idf/components/nvs_flash/include -I/home/psirus/Code/C/esp-idf/components/spi_flash/include -I/home/psirus/Code/C/esp-idf/components/mbedtls/port/include -I/home/psirus/Code/C/esp-idf/components/mbedtls/mbedtls/include -I/home/psirus/Code/C/esp-idf/components/app_update/include -I/home/psirus/Code/C/esp-idf/components/bootloader_support/include -mlongcalls -Wno-frame-address   -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -nostdlib -Wall -Werror=all -Wno-error=unused-function -Wno-error=unused-but-set-variable -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wextra -Wno-unused-parameter -Wno-sign-compare -ggdb -Og -std=gnu99 -Wno-old-style-declaration -Wno-unused-label -Wno-discarded-qualifiers -Wno-ignored-qualifiers -Wno-error=unused-label -Wno-error=parentheses -Wno-error=implicit-function-declaration -Wno-error=maybe-uninitialized -Wno-error=nonnull -Wno-error=address -Wno-unused-but-set-variable -D_GNU_SOURCE -DIDF_VER=\"v4.0.2-442-g41efdb0b3\" -DGCC_NOT_5_2_0 -DESP_PLATFORM -MD -MT 'esp-idf/main/CMakeFiles/__idf_main.dir/nimcache/@mesp32_nim_test.nim.c.obj' -MF esp-idf/main/CMakeFiles/__idf_main.dir/nimcache/@mesp32_nim_test.nim.c.obj.d -o 'esp-idf/main/CMakeFiles/__idf_main.dir/nimcache/@mesp32_nim_test.nim.c.obj'   -c '../main/nimcache/@mesp32_nim_test.nim.c'
In file included from ../main/nimcache/@mesp32_nim_test.nim.c:8:
../main/nimcache/nimbase.h:275:47: error: size of array 'NIM_STATIC_ASSERT_AUX' is negative
 #define NIM_STATIC_ASSERT(x, msg) typedef int NIM_STATIC_ASSERT_AUX[(x) ? 1 : -1];
                                               ^~~~~~~~~~~~~~~~~~~~~
../main/nimcache/nimbase.h:542:1: note: in expansion of macro 'NIM_STATIC_ASSERT'
 NIM_STATIC_ASSERT(sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8, "");
 ^~~~~~~~~~~~~~~~~

The same error appears for "stdlib_io.nim.c.obj" and "stdlib_system.nim.c.obj". For the latter, it also says

../main/nimcache/stdlib_system.nim.c:11:10: fatal error: sys/mman.h: No such file or directory
 #include <sys/mman.h>
          ^~~~~~~~~~~~

Any help would be appreciated. Thanks for this project BTW!

Edit: So it seems nim writes #define NIM_INTBITS 64 into the start of the generated C code. And as far as I understand it, there should be a 32 there. Maybe it doesn't pick up the --cpu:esp option for some reason? It is in main/nim.cfg.

GPIO with delay issue.

Hi, thanks for the awesome lib. I am using it with LilyGO T-Beam.
I am successfully using uart with GPS and I am very excited about it. While i was trying to setup the I2C i wanted to test if i am using the right pins. So I used the GPIO configure with delayMillis. While i was mixing this two lines the fw freezes. This happens on pins 21 and 22 (I2C pins) but not on 23. Do you have any idea?

  proc printf*(formatstr: cstring) {.importc: "printf", varargs, header: "stdio.h".}

  printf("output\n")
  {GPIO_NUM_23}.configure(MODE_OUTPUT)
  delay(Millis(100))
  printf("false\n")
  GPIO_NUM_23.setLevel(false) 
  delay(Millis(100))
  printf("true\n")
  GPIO_NUM_23.setLevel(true)
  delay(Millis(100))
  printf("false\n")
  GPIO_NUM_23.setLevel(false)

  printf("output\n")
  {GPIO_NUM_21}.configure(MODE_OUTPUT)
  delay(Millis(100))
  printf("false\n")
  GPIO_NUM_21.setLevel(false) 
  delay(Millis(100))
  printf("true\n")
  GPIO_NUM_21.setLevel(true)
  #CRASH
  delayMillis(100)
  printf("false\n")
  GPIO_NUM_21.setLevel(false) 

SSL support

I was wondering if any progress had been made yet on SSL support? Namely I just tried getting the nim_imap library working but getting horribly deep stack traces due to it's usage of wrapsocket -> nim's net lib -> openssl (ends up calling into dynlib to load up openssl dynamically I assume).

Any clue how I could fix this? I imagine I need to somehow replace the openssl wrapper? Would love to help!

ESP crashes when using UART `read()`

Disclaimer: I don't know what I'm doing, I have very little experience with electronics and embedded development. Maybe its just a daft beginner mistake.

I'm trying to use the UART module to read in MIDI data. This is the code:

import nesper
import nesper/gpios
import nesper/timers
import nesper/uarts

app_main():
  var uart_config = newUartConfig(baud_rate=31250)
  var uart = newUart(uart_config, UART_NUM_2, GPIO_PIN(14), GPIO_PIN(34), buffer=1024.SzBytes)
  while true:
    delayMillis(100)
    var buff = uart.read()
    if buff.len != 0:
      echo buff

And it works, for a little while. After a couple of seconds (it varies), the ESP either becomes unresponsive or crashes. A backtrace from one of the crashes is here. Thanks for your help.

Edit: I was able to work around this problem by copying the nim code from read() and moving the creation of the buffer outside of the loop. Maybe the temporary buffer isn't garbage collected, or read isn't supposed to be used in a loop like this, or something else I don't quite grasp.

Compile error: Unknown type name 'esp_timer' when calling createTimer()

When setting up a timer in my code:

    proc timerSetup() =
      let timerHandle = createTimer(timerTriggered, nil, ESP_TIMER_TASK, "HVAC_TIMEOUT")
      check: esp_timer_start_periodic(timerHandle, TIMEOUT.toMicros.uint64)

I get a compile error while running make:

/root/.nimble/pkgs/nesper-#0.5.0/nesper/timers.nim:17:25: error: unknown type name 'esp_timer'
/root/.nimble/pkgs/nesper-#0.5.0/nesper/timers.nim:17:223: error: unknown type name 'esp_timer'; use 'struct' keyword to refer to the type
/root/.nimble/pkgs/nesper-#0.5.0/nesper/timers.nim:17:279: error: unknown type name 'esp_timer'; use 'struct' keyword to refer to the type
/root/.nimble/pkgs/nesper-#0.5.0/nesper/timers.nim:17:366: error: 'esp_timer' undeclared (first use in this function)
/root/.nimble/pkgs/nesper-#0.5.0/nesper/timers.nim:17:376: error: expected expression before ')' token
/root/.nimble/pkgs/nesper-#0.5.0/nesper/timers.nim:17:472: error: expected expression before ')' token
../main/nimcache/@mhvac_controller.nim.c:153:25: error: unknown type name 'esp_timer'
/project/main/hvac_controller.nim:99:79: error: unknown type name 'esp_timer'; use 'struct' keyword to refer to the type
make: *** [build] Error 2

Any idea why compilation is failing?

Setup CI Builds for all supported examples

Setup CI to run all unit tests and then also run a full build against ESP-IDF. Ideally this could be expanded to include all stable branches of ESP-IDF as well but esp-idf v4.0 is currently the only one I am manually verifying.

Error while running esp_build on windows

Hello,

This issue is from copy of a post on this thread.

I have been following the installation guide on your github page and having an issue with nimbe esp_setup that throws out this error:

C:\Users\[user]\.nimble\pkgs2\nesper-0.6.1-9d526d2ec182747c58d820da1742d7a0d3d4647d\nesper\build_utils\tasks.nim(71, 5) Error: unhandled exception: error running getting Nesper path using: `%#` [ValueError]
nimscriptwrapper.nim(160) execScript
    
    Error:  Exception raised during nimble script execution

I have a fresh version of esp-idf, I am running on windows 10. I tried multiple things like uninstalling and reinstalling nesper, running the command in both powershell and normal terminal .
When I copy line 67-69 to a new .nim file and execute it I don't get any error...

Guru Meditation Error: Core 0 panic'ed (StoreProhibited).

Hello,

I am trying to user Nesper to build a web server which serves page generated by Karax.
The generated JavaScript file is huge - 150kB right now - and I am trying to load it into const variable at compile time. Project builds, flashes, and starts fine.

const karax_js = staticRead("webpage_dynamic.js")

proc cb*(req: Request) {.async.} =
    inc count
    echo "req #", count
    await req.respond(Http200, karax_js) 
    # GC_fullCollect()

However, when I want to access my server, it show me this error and ESP restarts.

Guru Meditation Error: Core  0 panic'ed (StoreProhibited). Exception was unhandled.
Core 0 register dump:
PC      : 0x4000c433  PS      : 0x00060530  A0      : 0x800f0e04  A1      : 0x3ffbb420  
A2      : 0x00000049  A3      : 0x00000000  A4      : 0x00022f96  A5      : 0x00000049  
A6      : 0x00000001  A7      : 0x00000000  A8      : 0x800f0de0  A9      : 0x3ffbb3f0  
A10     : 0x00000000  A11     : 0x00022fdf  A12     : 0x00000049  A13     : 0x00000016  
A14     : 0x3ffcf688  A15     : 0x3ffb4850  SAR     : 0x00000004  EXCCAUSE: 0x0000001d  
EXCVADDR: 0x00000049  LBEG    : 0x4000c28c  LEND    : 0x4000c296  LCOUNT  : 0x00000000  

ELF file SHA256: 5c656b0aefdfc118

Backtrace: 0x4000c430:0x3ffbb420 0x400f0e01:0x3ffbb430 0x400f0e11:0x3ffbb450 0x400f220c:0x3ffbb470 0x400e2c62:0x3ffbb490 0x400fa567:0x3ffbb4e0 0x400fa609:0x3ffbb520 0x400fb339:0x3ffbb550 0x400e559f:0x3ffbb590 0x400ddb60:0x3ffbb640 0x400d80b2:0x3ffbb670 0x400d8832:0x3ffbb6b0 0x400d8869:0x3ffbba40 0x400d8897:0x3ffbba60 0x400fb415:0x3ffbba80 0x400d6703:0x3ffbbac0 0x400d67d9:0x3ffbbaf0 0x400d24b2:0x3ffbbb20 0x40087c81:0x3ffbbb40
0x400f0e01: nimSetMem__JE6t4x7Z3v2iVz27Nx0MRAmemory at /home/ado/.choosenim/toolchains/nim-1.4.2/lib/system/memory.nim:24
 (inlined by) nimZeroMem at /home/ado/.choosenim/toolchains/nim-1.4.2/lib/system/memory.nim:34
 (inlined by) zeroMem__9cLyRtoQz0YlIMEd4qW7Hdgsystem at /home/ado/.choosenim/toolchains/nim-1.4.2/lib/system.nim:2169
 (inlined by) realloc0Impl__Jvtux8Lvp7XxQp3KVEEn5A_2 at /home/ado/.choosenim/toolchains/nim-1.4.2/lib/system/mm/malloc.nim:16

0x400f0e11: reallocShared0Impl__Jvtux8Lvp7XxQp3KVEEn5A at /home/ado/.choosenim/toolchains/nim-1.4.2/lib/system/mm/malloc.nim:34

0x400f220c: prepareAdd at /home/ado/.choosenim/toolchains/nim-1.4.2/lib/system/strs_v2.nim:59

0x400e2c62: respond__tA4fbg9cx0zS1ZvSTtksr9bQ at /home/ado/.choosenim/toolchains/nim-1.4.2/lib/pure/asynchttpserver.nim:122

0x400fa567: cbIter__AHZINeUSKXBCYMn6ufJ0GA at /home/ado/Desktop/Projects/Bc/nesper-projects/simplewifi/esp32/main/server.nim:12 (discriminator 3)

0x400fa609: cbNimAsyncContinue__9caCnUj9axdJsQyMol6wITVg at /home/ado/.choosenim/toolchains/nim-1.4.2/lib/pure/asyncmacro.nim:29

0x400fb339: cb__LlziUBgZQLrEXWFU4ognqg at /home/ado/.choosenim/toolchains/nim-1.4.2/lib/pure/asyncmacro.nim:262 (discriminator 1)

0x400e559f: processRequestIter__9bFW7o03uH9aU8ZP0CEQpILA_3 at /home/ado/.choosenim/toolchains/nim-1.4.2/lib/pure/asynchttpserver.nim:271 (discriminator 4)

0x400ddb60: processRequestNimAsyncContinue__0f5XHRBN20CBOjiT69cdDnQ at /home/ado/.choosenim/toolchains/nim-1.4.2/lib/pure/asyncmacro.nim:32 (discriminator 2)

0x400d80b2: processPendingCallbacks__xdICRvJ1ns9byYHPjM07uJQ at /home/ado/.choosenim/toolchains/nim-1.4.2/lib/pure/asyncdispatch.nim:208 (discriminator 3)

0x400d8832: runOnce__nEnn7ilZ6aSkcXTtLEKnJA at /home/ado/.choosenim/toolchains/nim-1.4.2/lib/pure/asyncdispatch.nim:1368 (discriminator 2)

0x400d8869: poll__wcvh7vf5dGU1VYto9aiAnpA at /home/ado/.choosenim/toolchains/nim-1.4.2/lib/pure/asyncdispatch.nim:1627

0x400d8897: waitFor__zz9aVsJN0aTuFUXvzKrFo9cA at /home/ado/.choosenim/toolchains/nim-1.4.2/lib/pure/asyncdispatch.nim:1935

0x400fb415: run_http_server at /home/ado/Desktop/Projects/Bc/nesper-projects/simplewifi/esp32/main/server.nim:19 (discriminator 2)

0x400d6703: exampleConnect__kC9aXobSCodwFuT7ilNTHxg at /home/ado/Desktop/Projects/Bc/nesper-projects/simplewifi/esp32/main/wifi_example_main.nim:87

0x400d67d9: app_main at /home/ado/Desktop/Projects/Bc/nesper-projects/simplewifi/esp32/main/wifi_example_main.nim:117 (discriminator 13)

0x400d24b2: main_task at /home/ado/esp/esp-idf/components/esp32/cpu_start.c:558 (discriminator 2)

0x40087c81: vPortTaskWrapper at /home/ado/esp/esp-idf/components/freertos/port.c:143


Rebooting...

I am using Nesper 0.5.0, Nim 1.4.2 and esp-idf release/v4.

I am now to ESP programming so I might be wrong, but I read consts should load into Flash memory (DROM) automatically (at least when declared in C) so there should be plenty of space? I think I could use NVS functions but I am not sure how.

If large file / data storage is possible with Nesper, could you please create a small example?

Thank you.

EDIT:
Running idf.py size gives me:

Total sizes:
 DRAM .data size:   14220 bytes
 DRAM .bss  size:   26008 bytes
Used static DRAM:   40228 bytes ( 140508 available, 22.3% used)
Used static IRAM:   88692 bytes (  42380 available, 67.7% used)
      Flash code:  650906 bytes
    Flash rodata:  272152 bytes
Total image size:~1025970 bytes (.bin may be padded larger)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.