Notes on A4988 component.

Looks very simple to use.
Test case illustrates basics:
  instantiate a stepper object with step/dir pins, steps per rev, etc.
      Multiple instances must not share LEDC_CHANNEL and PCNT_UNITS
        (perhaps other similar-sounding params too?)
      ...need to better understand these terms.

  To use, call object methods:

    step()              -- turn specified # of steps.  Sign indicates direction
    wait()              -- wait for steps to finish
    run()               -- turn on continuous motion
    stop()              -- stop continuous motion --will it also interrupt a step() method?
    setSpeedRPM()       -- set target speed (will accel to this target normally)
    setSpeedCur()       -- set speed immediately
    getSpeedRPM()       -- get current speed
    getSpeedRPMTarget() -- get target speed

- - - -

Monitor pass looks like this:
--
stepper_test $ make monitor
Toolchain path: /Users/mkeveney/esp/xtensa-esp32-elf/bin/xtensa-esp32-elf-gcc
Toolchain version: crosstool-ng-1.22.0-80-g6c4433a
Compiler version: 5.2.0
Python requirements from /Users/mkeveney/esp-idf/requirements.txt are satisfied.
MONITOR
--- WARNING: Serial ports accessed as /dev/tty.* will hang gdb if launched.
--- Using /dev/cu.SLAB_USBtoUART instead...
--- idf_monitor on /dev/cu.SLAB_USBtoUART 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:6144
ho 0 tail 12 room 4
load:0x40078000,len:10180
load:0x40080400,len:6640
entry 0x40080760
I (30) boot: ESP-IDF v3.2 2nd stage bootloader
I (30) boot: compile time 20:04:01
I (30) boot: Enabling RNG early entropy source...
I (35) boot: SPI Speed      : 40MHz
I (39) boot: SPI Mode       : DIO
I (43) boot: SPI Flash Size : 4MB
I (47) boot: Partition Table:
I (51) boot: ## Label            Usage          Type ST Offset   Length
I (58) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (65) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (73) boot:  2 factory          factory app      00 00 00010000 00100000
I (80) boot: End of partition table
I (84) esp_image: segment 0: paddr=0x00010020 vaddr=0x3f400020 size=0x0a184 ( 41348) map
I (108) esp_image: segment 1: paddr=0x0001a1ac vaddr=0x3ffb0000 size=0x01eb4 (  7860) load
I (111) esp_image: segment 2: paddr=0x0001c068 vaddr=0x40080000 size=0x00400 (  1024) load
0x40080000: _WindowOverflow4 at /Users/mkeveney/esp-idf/components/freertos/xtensa_vectors.S:1779

I (115) esp_image: segment 3: paddr=0x0001c470 vaddr=0x40080400 size=0x03ba0 ( 15264) load
I (130) esp_image: segment 4: paddr=0x00020018 vaddr=0x400d0018 size=0x14e4c ( 85580) map
0x400d0018: _flash_cache_start at ??:?

I (162) esp_image: segment 5: paddr=0x00034e6c vaddr=0x40083fa0 size=0x059cc ( 22988) load
0x40083fa0: stepper_pcnt_intr_handler at /Users/mkeveney/src/esp/stepper_test/components/a4988/a4988.cpp:306

I (178) boot: Loaded app from partition at offset 0x10000
I (178) boot: Disabling RNG early entropy source...
I (179) cpu_start: Pro cpu up.
I (182) cpu_start: Starting app cpu, entry point is 0x40080eb8
0x40080eb8: call_start_cpu1 at /Users/mkeveney/esp-idf/components/esp32/cpu_start.c:246

I (0) cpu_start: App cpu up.
I (193) heap_init: Initializing. RAM available for dynamic allocation:
I (199) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (206) heap_init: At 3FFB2F48 len 0002D0B8 (180 KiB): DRAM
I (212) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (218) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (225) heap_init: At 4008996C len 00016694 (89 KiB): IRAM
I (231) cpu_start: Pro cpu start user code
I (249) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.

- - - this looks like trouble

E (251) ledc: ledc_set_duty_with_hpoint(383): hpoint argument is invalid
I (251) gpio: GPIO[19]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (261) stepper_a4988: set freq: 720

I (271) stepper_a4988: set freq: 120

- - - and so does this.

E (271) ledc: div param err,div_param=1333333
Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC      : 0x4008692b  PS      : 0x00060730  A0      : 0x800869fa  A1      : 0x3ffb66b0
0x4008692b: prvProcessReceivedCommands at /Users/mkeveney/esp-idf/components/freertos/timers.c:962

A2      : 0x00000000  A3      : 0x00000000  A4      : 0x00000001  A5      : 0x00000001
A6      : 0x00060021  A7      : 0x00000000  A8      : 0x00000008  A9      : 0x3ffb6670
A10     : 0x00000001  A11     : 0x00000000  A12     : 0x3ffb5ef8  A13     : 0x00000000
A14     : 0x3ffb5f90  A15     : 0x00060023  SAR     : 0x00000000  EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000014  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0x00000000

Backtrace: 0x4008692b:0x3ffb66b0 0x400869f7:0x3ffb66f0 0x400845d5:0x3ffb6720
0x4008692b: prvProcessReceivedCommands at /Users/mkeveney/esp-idf/components/freertos/timers.c:962

0x400869f7: prvTimerTask at /Users/mkeveney/esp-idf/components/freertos/timers.c:962

0x400845d5: vPortTaskWrapper at /Users/mkeveney/esp-idf/components/freertos/port.c:403


Rebooting...
- - - -
Then it repeats forever
------

Looks like the 'hpoint' argument is indeed missing, probably the A4988 module was written for an earlier revision.

https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/ledc.html
http://iot-bits.com/esp32/esp32-led-pwm-controller-example-sample-code/

-----
5/4/19

set hpoint and inter_type to sensible defaults.  Now getting
div param err,div_param=1333333
  in ledc_set_frequency()
  max is 3FFFF; we're at 1333333 or 0x145855
  Thinking our selected speed is too slow for the timer frequency.
  go from 10 to 100 & see

That fixed the error, but now we get 'unhandled exception':

    .
    .
    I (261) stepper_a4988: set freq: 1200

    Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.
    Core 0 register dump:
    PC      : 0x4008692b  PS      : 0x00060730  A0      : 0x800869fa  A1      : 0x3ffb66b0
    0x4008692b: prvProcessReceivedCommands at /Users/mkeveney/esp-idf/components/freertos/timers.c:962

    A2      : 0x00000000  A3      : 0x00000000  A4      : 0x00000001  A5      : 0x00000001
    A6      : 0x00060021  A7      : 0x00000000  A8      : 0x00000008  A9      : 0x3ffb6670
    A10     : 0x00000001  A11     : 0x00000000  A12     : 0x3ffb5ef8  A13     : 0x00000000
    A14     : 0x3ffb5f90  A15     : 0x00060023  SAR     : 0x00000000  EXCCAUSE: 0x0000001c
    EXCVADDR: 0x00000014  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0x00000000

    Backtrace: 0x4008692b:0x3ffb66b0 0x400869f7:0x3ffb66f0 0x400845d5:0x3ffb6720
    0x4008692b: prvProcessReceivedCommands at /Users/mkeveney/esp-idf/components/freertos/timers.c:962

    0x400869f7: prvTimerTask at /Users/mkeveney/esp-idf/components/freertos/timers.c:962

    0x400845d5: vPortTaskWrapper at /Users/mkeveney/esp-idf/components/freertos/port.c:403

--
  enabled core dump; not much help.
  also changed panic handler to 'halt' instead of 'reboot'

  fatal-errors.rst is a good read.  Cause is in parentheses.  In this case
  'LoadProhibited' which is read/write to invalid location.
  EXCVADDR is 0x00000014; so something tried to read/write there.
  for low addresses like this, something probably tried to read/write to
  a structure member, but struct pointer was null.
  Near 962
    could it be xTimer->xTimerListItem? ... Doesn't seem likely; just one pointer param ahead of it
    Wondering where 'port' trace fits in.
    In that file, CONFIG_FREERTOS_CORETIMER_0 (which we've defined) is referenced.
    Wondering if maybe something else is trying to use the hardware timer
    that a4988 selects (by default).  Let's change it!

-- no change at all.
  Changing back to zero.
  Looking at timers in a4988
  This happens right after a4988 set's freq to 1200.
    ...debugging code in set freq seems OK.
  debugging code in main doesn't help much; interestingly we get past the set frequency _before_ the corresponding debug output from a4988.  Different cores? threads?
    turns out a4988 set freq is not called until step().

  ::step() seems to happen fine.  We crash inside vtaskdelay _after_ step.
    added extra vtaskdelays upstream to confirm.

---
stumped.
Need to better understand timer usage
  looks like a4988 uses a timer (::tmr) to accelerate.
  And LEDC uses a timer as well.

reading esp32 docs:
  There are four hardware timers, two 'groups' of two timers each
  timer_get_cfg() can be used to get params:
    alarm enable
    counter enable
    interrupt level - if running in alarm mode; but only has one level: 0
    counter_dir - down or up
    auto_reload
    divider - 2 to 65536; divides an 80mhz system clock?
    ...not sure we're really using this api.
    looks like xTimer--- methods in a4988.cpp resolve to timers.c, described as software timers (in freertos directory).

also wondering if I simply have the wrong esp-idf.  The iot-solution project specifies idf as a submodule... have to get good wifi somewhere & update it.
  Remember to point IDF_PATH directory to the submodule before building.  Then, track down differences if that does it.

------
a4988 component working?

I want to drive stepper motors, so I'm trying out the a4988 component.

No luck so far.

With code straight from the repo, I get this:

    .
    .
    E (247) ledc: ledc_set_duty_with_hpoint(383): hpoint argument is invalid
    .
    .

Looking at the a4988.cpp(), it appears that the ledc init code never set
this 'hpoint' parameter.  Perhaps that was for an earlier version of ESP-IDF?
The intr_type paramter is also missing.

So, I updated a4988.cpp to initialize these to (what I assume to be) reasonable defaults:

  ledc_ch.intr_type  = LEDC_INTR_DISABLE;
  ledc_ch.hpoint     = 0;

This cures the 'hpoint' error, but now I get a 'LoadProhibited' crash:

    Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.
    Core 0 register dump:
    PC      : 0x40086423  PS      : 0x00060930  A0      : 0x800864f2  A1      : 0x3ffb6ae0
    0x40086423: prvProcessReceivedCommands at /Users/mkeveney/src/esp/esp-iot-solution/submodule/esp-idf/components/freertos/timers.c:961

    A2      : 0x00000000  A3      : 0x00000000  A4      : 0x00000001  A5      : 0x3ffb51b4
    A6      : 0x00000000  A7      : 0x00000001  A8      : 0x00000008  A9      : 0x3ffb6aa0
    A10     : 0x00000001  A11     : 0x00000000  A12     : 0x3ffb6314  A13     : 0x00000000
    A14     : 0x3ffb63ac  A15     : 0x00000000  SAR     : 0x00000000  EXCCAUSE: 0x0000001c
    EXCVADDR: 0x00000014  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0x00000000

    Backtrace: 0x40086423:0x3ffb6ae0 0x400864ef:0x3ffb6b20
    0x40086423: prvProcessReceivedCommands at /Users/mkeveney/src/esp/esp-iot-solution/submodule/esp-idf/components/freertos/timers.c:961

    0x400864ef: prvTimerTask at /Users/mkeveney/src/esp/esp-iot-solution/submodule/esp-idf/components/freertos/timers.c:961

The EXCVADDR 0x0000014 suggests a null reference to a struct, but there doesn't seem to be such a reference near the code referenced in the backtrace.  Am I missing something obvious?

My code is almost verbatim from the unit test:

    CA4988Stepper stepper(CONFIG_STEP_GPIO, CONFIG_DIR_GPIO, STEPS_PER_REV,
        LEDC_HIGH_SPEED_MODE, LEDC_TIMER_0);

    stepper.setSpeedRpm(80);
    stepper.step(100);
    vTaskDelay(1000/portTICK_RATE_MS);      // crash happens during this delay.
    stepper.step(-100);
    vTaskDelay(1000/portTICK_RATE_MS);

Has anyone ever got this component working?  What's the secret?

-Matt

-------
About the only forum post I've found on the subject
https://www.esp32.com/viewtopic.php?t=1223

Maybe go through ledc examples, etc. to better understand that.  How does it interact with the hardware or software timers, if at all?

..also PCNT example, which specifically counts rising edges generated by LEDC
    How does this work? Docs seem to suggest PCNT counts rising edges of an _input_ pin...






