Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PDM support for I2S #1

Closed

Conversation

thiswillbeyourgithub
Copy link

@thiswillbeyourgithub thiswillbeyourgithub commented Dec 23, 2023

All the text below is now irrelevant because of @Lana-chan 's PR. I'm now trying to merge it with @jeffmer 's GPIO commit. To keep track of the changes go to my fork

Hi,

So I made this draft PR to keep track and report on what I tried to get a recent micropython driver for the twatch V3 that supports PDM.

The idea came from this message from @devnoname120 where he mentions this repo by @lemariva which states:

This repository adds I2S support to MicroPython for the ESP32 family. The code was taken from the PR, and was updated and modified to include the I2S-PDM mode. This mode is required by some MEMS microphones e.g. SPM1423.

I first tried to build and flash the most recent micropython using @jeffmer 's commit for GPIO_WAKEUP.

Building the recent micropython

Steps I took to build and flash the recent micropython with GPIO_WAKEUP:
(The instructions to build then compile were from this README)

  1. git clone -b v5.0.2 --recursive https://github.com/espressif/esp-idf.git
  2. cd esp-idf && git checkout v5.0.2 && git submodule update --init --recursive && ./install.sh && source export.sh
    Note: I think all of this has to happen in the same terminal window because the esp-idf export.sh changes some PATH needed for the make command
  3. cd .. && git clone https://github.com/jeffmer/micropython/
  4. cd micropython && make -C mpy-cross && cd ports/esp32 && make submodules && make BOARD=ESP32_GENERIC BOARD_VARIANT=SPIRAM
  5. python -m esptool --port /dev/ttyACM0 erase_flash
  6. To flash using the commands from esp-idf you can use the command given as a final output from the make command. (something like /home/USER/.espressif/python_env/idf5.0_py3.10_env/bin/python ../../../esp-idf/components/esptool_py/esptool/esptool.py -p /dev/ttyACM0 -b 460800 --before default_reset --after hard_reset --chip esp32 write_flash --flash_mode dio --flash_size 4MB --flash_freq 40m 0x1000 build-ESP32_GENERIC-SPIRAM/bootloader/bootloader.bin 0x8000 build-ESP32_GENERIC-SPIRAM/partition_table/partition-table.bin 0x10000 build-ESP32_GENERIC-SPIRAM/micropython.bin). I think you can alternatively use python -m esptool --port /dev/ttyACM0 --chip esp32 write_flash -z 0x1000 build-ESP32_GENERIC-SPIRAM/firmware.bin
  7. cd .. && git clone https://github.com/jeffmer/TTGO-T-watch-2020-Micropython-OS/ && cd TTGO-T-watch-2020-Micropython-OS/src
  8. modify the path to mpy-cross in compile.sh to point to the one built in the micropython folder
  9. ./compile.sh
  10. ./install.sh

This was succesful and produced a build that flashed without issues on my V3 watch.

Now, to get the commit from @lemariva working without knowing any C I had to do some modifications to the commit code. As I don't know C I don't really know if some of my changes invalidated the commit or not but I got it flashing and booting as normal.

Trying to add PDM support

There are 4 files in @lemariva's commit:

modmachine.h

  • I added all the missing lines from the commit to the micropython branch. That amounted to:
    +extern const mp_obj_type_t machine_hw_i2s_type;
    +extern const mp_obj_type_t machine_timer_type;
    +extern const mp_obj_type_t machine_wdt_type;
    +extern const mp_obj_type_t machine_pin_type;
    +extern const mp_obj_type_t machine_adc_type;
    +extern const mp_obj_type_t machine_pwm_type;
    +extern const mp_obj_type_t machine_hw_i2c_type;
    +extern const mp_obj_type_t machine_hw_spi_type;
    +extern const mp_obj_type_t machine_uart_type;
    +extern const mp_obj_type_t machine_rtc_type;
    

modmachine.c

  • I needed to add + { MP_ROM_QSTR(MP_QSTR_I2S), MP_ROM_PTR(&machine_hw_i2s_type) }, \ in the section wake abilities but I ran into some issues so I ended up moving typedef enum and a declaration of is_soft_reset just a bit higher in the code.

Makefile

  • apparently I needed to add a line to make sure that make would compile machine_i2s.c but the Makefile changed at lot between the recent micropython and the one for @lemariva so I ended up ignoring this step as I think the Makefile was using a glob to compile all *.c files. Given that I add compiling issue in machine_i2s.c I think this was true.

machine_i2s.c

  • so apparently this file did not exist in micropython at the time of lemariva so at the time I just needed to add it directly. But now there is a machine_i2s.c file in micropython so I needed to somehow merge the changes.

  • What I did was paste the whole machine_i2s.c file from lemariva at the end of the recent one, try to compile then make sense of the errors.

  • I also added at the top some #include statements.

The first change was fixed by @DonvdH in this message
* The first notable change was that in lemariva there is a line:

STATIC machine_hw_i2s_obj_t machine_hw_i2s_obj[I2S_NUM_MAX] = {
        [0].used = false,
        [1].used = false };

that returned error:

/home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/machine_i2s.c:510:48: error: 'I2S_NUM_MAX' undeclared here (not
 in a function); did you mean 'I2S_NUM_1'?

So I changed I2S_NUM_MAX to I2S_NUM_1 and got:

In file included from /home/USER/twatch_microphone/jeffmer_micropython/extmod/machine_i2s.c:128:
/home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/machine_i2s.c:512:10: error: array index in initializer exceeds
 array bounds                                                                                                                        512 |         [1].used = false };                                                                                                      |          ^

So I tried I2S_NUM_0 and got the same.
Finally tried with I2S_NUM_AUTO and got it passed that line.

I have no idea what I'm doing.

  • The second most notable change was that at the end of the file, lemariva ended up with:
const mp_obj_type_t machine_hw_i2s_type = {
{ &mp_type_type },
.name = MP_QSTR_I2S,
.print = machine_hw_i2s_print,
.make_new = machine_hw_i2s_make_new,
.locals_dict = (mp_obj_dict_t *) &machine_hw_i2s_locals_dict,
};

which returned errors like error: 'mp_obj_type_t' {aka 'const struct _mp_obj_type_t'} has no member named 'locals_dict' also for .make_new and .print.
Noticing that the end of machine_i2c.c ended up with a similar looking bunch of lines I intuitively merged it to:

MP_DEFINE_CONST_OBJ_TYPE(
machine_hw_i2s_type,
MP_QSTR_I2S,
MP_TYPE_FLAG_NONE,
make_new, machine_hw_i2s_make_new,
print, machine_hw_i2s_print,
locals_dict, (mp_obj_dict_t *) &machine_hw_i2s_locals_dict
);

which produced a build that apparently worked and successfuly built.

I think it was successful in the sense that it resulted in a flashable build, but I got many warnings and no errors, but all from machine_i2s. Here are the warnigs I got:

twatch_microphone/jeffmer_micropython/py/mpstate.h:35,
             from /home/USER/twatch_microphone/jeffmer_micropython/py/runtime.h:29,
             from /home/USER/twatch_microphone/jeffmer_micropython/extmod/machine_i2s.c:28:
/home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/machine_i2s.c:770:63: warning: initialization of 'void * (*)(size_t,  void * const*, mp_map_t *)' {aka 'void * (*)(unsigned int,  void * const*, struct _mp_map_t *)'} from incompatible pointer type 'void * (*)(mp_uint_t,  void * const*, mp_map_t *)' {aka 'void * (*)(long unsigned int,  void * const*, struct _mp_map_t *)'} [-Wincompatible-pointer-types]
  770 | STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_hw_i2s_init_obj, 1, machine_hw_i2s_init);
      |                                                               ^~~~~~~~~~~~~~~~~~~
/home/USER/twatch_microphone/jeffmer_micropython/py/obj.h:391:104: note: in definition of macro 'MP_DEFINE_CONST_FUN_OBJ_KW'
  391 |     {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun.kw = fun_name}
      |                                                                                                        ^~~~~~~~
/home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/machine_i2s.c:770:63: note: (near initialization for 'machine_hw_i2s_init_obj.fun.kw')
  770 | STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_hw_i2s_init_obj, 1, machine_hw_i2s_init);
      |                                                               ^~~~~~~~~~~~~~~~~~~
/home/USER/twatch_microphone/jeffmer_micropython/py/obj.h:391:104: note: in definition of macro 'MP_DEFINE_CONST_FUN_OBJ_KW'
  391 |     {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun.kw = fun_name}
      |                                                                                                        ^~~~~~~~
In file included from /home/USER/twatch_microphone/jeffmer_micropython/extmod/machine_i2s.c:128:
/home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/machine_i2s.c: In function 'machine_hw_i2s_readinto':
/home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/machine_i2s.c:800:66: warning: passing argument 4 of 'i2s_read' from incompatible pointer type [-Wincompatible-pointer-types]
  800 |     esp_err_t ret = i2s_read(self->id, bufinfo.buf, bufinfo.len, &num_bytes_read, timeout_in_ticks);
      |                                                                  ^~~~~~~~~~~~~~~
      |                                                                  |
      |                                                                  uint32_t * {aka long unsigned int *}
In file included from /home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/mpconfigport.h:12,
                 from /home/USER/twatch_microphone/jeffmer_micropython/py/mpconfig.h:91,
                 from /home/USER/twatch_microphone/jeffmer_micropython/py/mpstate.h:31,
                 from /home/USER/twatch_microphone/jeffmer_micropython/py/runtime.h:29,
                 from /home/USER/twatch_microphone/jeffmer_micropython/extmod/machine_i2s.c:28:
/home/USER/twatch_microphone/esp-idf/components/driver/deprecated/driver/i2s.h:208:73: note: expected 'size_t *' {aka 'unsigned int *'} but argument is of type 'uint32_t *' {aka 'long unsigned int *'}
  208 | esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_read, TickType_t ticks_to_wait);
      |                                                                 ~~~~~~~~^~~~~~~~~~
In file included from /home/USER/twatch_microphone/jeffmer_micropython/py/mpstate.h:35,
                 from /home/USER/twatch_microphone/jeffmer_micropython/py/runtime.h:29,
                 from /home/USER/twatch_microphone/jeffmer_micropython/extmod/machine_i2s.c:28:
/home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/machine_i2s.c: At top level:
/home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/machine_i2s.c:815:67: warning: initialization of 'void * (*)(size_t,  void * const*, mp_map_t *)' {aka 'void * (*)(unsigned int,  void * const*, struct _mp_map_t *)'} from incompatible pointer type 'void * (*)(mp_uint_t,  void * const*, mp_map_t *)' {aka 'void * (*)(long unsigned int,  void * const*, struct _mp_map_t *)'} [-Wincompatible-pointer-types]
  815 | STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_hw_i2s_readinto_obj, 2, machine_hw_i2s_readinto);
      |                                                                   ^~~~~~~~~~~~~~~~~~~~~~~
/home/USER/twatch_microphone/jeffmer_micropython/py/obj.h:391:104: note: in definition of macro 'MP_DEFINE_CONST_FUN_OBJ_KW'
  391 |     {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun.kw = fun_name}
      |                                                                                                        ^~~~~~~~
/home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/machine_i2s.c:815:67: note: (near initialization for 'machine_hw_i2s_readinto_obj.fun.kw')
  815 | STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_hw_i2s_readinto_obj, 2, machine_hw_i2s_readinto);
      |                                                                   ^~~~~~~~~~~~~~~~~~~~~~~
/home/USER/twatch_microphone/jeffmer_micropython/py/obj.h:391:104: note: in definition of macro 'MP_DEFINE_CONST_FUN_OBJ_KW'
  391 |     {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun.kw = fun_name}
      |                                                                                                        ^~~~~~~~
In file included from /home/USER/twatch_microphone/jeffmer_micropython/extmod/machine_i2s.c:128:
/home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/machine_i2s.c: In function 'machine_hw_i2s_write':
/home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/machine_i2s.c:845:67: warning: passing argument 4 of 'i2s_write' from incompatible pointer type [-Wincompatible-pointer-types]
  845 |     esp_err_t ret = i2s_write(self->id, bufinfo.buf, bufinfo.len, &num_bytes_written, timeout_in_ticks);
      |                                                                   ^~~~~~~~~~~~~~~~~~
      |                                                                   |
      |                                                                   uint32_t * {aka long unsigned int *}
In file included from /home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/mpconfigport.h:12,
                 from /home/USER/twatch_microphone/jeffmer_micropython/py/mpconfig.h:91,
                 from /home/USER/twatch_microphone/jeffmer_micropython/py/mpstate.h:31,
                 from /home/USER/twatch_microphone/jeffmer_micropython/py/runtime.h:29,
                 from /home/USER/twatch_microphone/jeffmer_micropython/extmod/machine_i2s.c:28:
/home/USER/twatch_microphone/esp-idf/components/driver/deprecated/driver/i2s.h:155:79: note: expected 'size_t *' {aka 'unsigned int *'} but argument is of type 'uint32_t *' {aka 'long unsigned int *'}
  155 | esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *bytes_written, TickType_t ticks_to_wait);
      |                                                                       ~~~~~~~~^~~~~~~~~~~~~
In file included from /home/USER/twatch_microphone/jeffmer_micropython/py/mpstate.h:35,
                 from /home/USER/twatch_microphone/jeffmer_micropython/py/runtime.h:29,
                 from /home/USER/twatch_microphone/jeffmer_micropython/extmod/machine_i2s.c:28:
/home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/machine_i2s.c: At top level:
/home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/machine_i2s.c:860:64: warning: initialization of 'void * (*)(size_t,  void * const*, mp_map_t *)' {aka 'void * (*)(unsigned int,  void * const*, struct _mp_map_t *)'} from incompatible pointer type 'void * (*)(mp_uint_t,  void * const*, mp_map_t *)' {aka 'void * (*)(long unsigned int,  void * const*, struct _mp_map_t *)'} [-Wincompatible-pointer-types]
  860 | STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_hw_i2s_write_obj, 2, machine_hw_i2s_write);
      |                                                                ^~~~~~~~~~~~~~~~~~~~
/home/USER/twatch_microphone/jeffmer_micropython/py/obj.h:391:104: note: in definition of macro 'MP_DEFINE_CONST_FUN_OBJ_KW'
  391 |     {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun.kw = fun_name}
      |                                                                                                        ^~~~~~~~
/home/USER/twatch_microphone/jeffmer_micropython/ports/esp32/machine_i2s.c:860:64: note: (near initialization for 'machine_hw_i2s_write_obj.fun.kw')
  860 | STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_hw_i2s_write_obj, 2, machine_hw_i2s_write);
      |                                                                ^~~~~~~~~~~~~~~~~~~~
/home/USER/twatch_microphone/jeffmer_micropython/py/obj.h:391:104: note: in definition of macro 'MP_DEFINE_CONST_FUN_OBJ_KW'
  391 |     {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun.kw = fun_name}
      |                                                                                                        ^~~~~~~~

At the end of all this I flashed the whole thing using the above commands and the watch booted successfuly. But now what? when doing from machine import I2S ; dir(I2S) I don't see a PDM mode, but I don't if that's expected or not. Basically I don't know if my commit was working or not, if it did change the build, if it added functionnality or not etc.

Please help

  • Can anyone tell me if the build appeared succesful?
  • Were my modification to micropython sane or did I botch it? I have a feeling that my merging of the machine_i2s.c files was a problem.
  • If my modifications worked, how should I test it? Reminder: my goal is to be able to record sounds on my watch.

@thiswillbeyourgithub
Copy link
Author

All the text above is now irrelevant because of @Lana-chan 's micropython#14176. I'm now trying to merge it with @jeffmer 's GPIO commit. To keep track of the changes go to my fork

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants