├── .gitignore ├── .vscode ├── c_cpp_properties.json ├── launch.json └── tasks.json ├── CMakeLists.txt ├── Kconfig ├── README.md ├── boards └── arm │ ├── printhat1 │ ├── Kconfig.board │ ├── Kconfig.defconfig │ ├── printhat1.dts │ └── printhat1_defconfig │ └── printhat2 │ ├── Kconfig.board │ ├── Kconfig.defconfig │ ├── printhat2.dts │ └── printhat2_defconfig ├── clear-west.sh ├── drivers ├── CMakeLists.txt ├── Kconfig ├── tmc │ ├── CMakeLists.txt │ ├── tmc.c │ ├── tmc.h │ ├── tmc_shell.c │ ├── tmc_shell.h │ ├── tmc_spi.c │ ├── tmc_spi.h │ ├── tmc_uart.c │ └── tmc_uart.h ├── tmc2130 │ ├── CMakeLists.txt │ ├── Kconfig │ └── src │ │ ├── tmc2130.c │ │ ├── tmc2130.h │ │ └── tmc2130_map.c ├── tmc2209 │ ├── CMakeLists.txt │ ├── Kconfig │ └── src │ │ ├── tmc2209.c │ │ ├── tmc2209.h │ │ └── tmc2209_map.c ├── tmc5160 │ ├── CMakeLists.txt │ ├── Kconfig │ └── src │ │ ├── tmc5160.c │ │ ├── tmc5160.h │ │ ├── tmc5160_map.c │ │ └── tmc5160_shell.c └── zephyr │ └── module.yml ├── dts └── bindings │ ├── trinamic,tmc.yml │ ├── trinamic,tmc2130-spi.yml │ ├── trinamic,tmc2209-uart.yml │ ├── trinamic,tmc5160-spi.yml │ └── trinamic,tmc5160-uart.yml ├── manifest-devel └── west.yml ├── samples ├── application │ ├── CMakeLists.txt │ ├── boards │ │ └── nucleo_f446ze.overlay │ ├── prj.conf │ └── src │ │ ├── com.c │ │ ├── com.h │ │ ├── common.h │ │ ├── led.c │ │ ├── led.h │ │ ├── main.c │ │ ├── sens.c │ │ ├── sens.h │ │ └── shell.c ├── printhat1 │ ├── CMakeLists.txt │ ├── prj.conf │ └── src │ │ └── main.c ├── printhat2 │ ├── CMakeLists.txt │ ├── prj.conf │ └── src │ │ └── main.c ├── single-wire-irq │ ├── CMakeLists.txt │ ├── boards │ │ └── nucleo_f103rb.overlay │ ├── prj.conf │ └── src │ │ └── main.c ├── single-wire │ ├── CMakeLists.txt │ ├── boards │ │ └── nucleo_f103rb.overlay │ ├── prj.conf │ └── src │ │ └── main.c ├── tmc-spi-sd │ ├── CMakeLists.txt │ ├── boards │ │ └── nucleo_f103rb.overlay │ ├── prj.conf │ └── src │ │ └── main.c ├── tmc-spi │ ├── CMakeLists.txt │ ├── boards │ │ └── nucleo_f103rb.overlay │ ├── prj.conf │ └── src │ │ └── main.c ├── tmc-uart-dma │ ├── CMakeLists.txt │ ├── boards │ │ └── nucleo_f103rb.overlay │ ├── prj.conf │ └── src │ │ └── main.c └── tmc-uart │ ├── CMakeLists.txt │ ├── boards │ └── nucleo_f103rb.overlay │ ├── prj.conf │ └── src │ └── main.c ├── west.yml ├── zephyr-trinamic.code-workspace └── zephyr └── module.yml /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | modules 3 | tools 4 | rtos 5 | .west 6 | .vscode/.cortex-debug.registers.state.json 7 | .vscode/*.log 8 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Zephyr", 5 | "includePath": [ 6 | "zephyr/include/**", 7 | "drivers/**", 8 | "modules/hal/**" 9 | ], 10 | "defines": [], 11 | "compilerPath": "/usr/bin/gcc", 12 | "cStandard": "gnu17", 13 | "cppStandard": "gnu++14", 14 | "intelliSenseMode": "linux-gcc-x64" 15 | } 16 | ], 17 | "version": 4 18 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | 8 | // board_runner_args(jlink "--device=STM32L475VG" "--speed=4000") 9 | 10 | // openocd 11 | { 12 | "name": "zephyr stm32f103rb", 13 | "type": "cortex-debug", 14 | "request": "launch", 15 | "servertype": "openocd", 16 | //"runToEntryPoint": "main", 17 | "cwd": "${workspaceRoot}", 18 | "executable": "build/zephyr/zephyr.elf", 19 | "device": "stm32f103rb", 20 | //"interface": "swd", 21 | //"armToolchainPath": "${HOME}/zephyr-sdk-0.14.2/arm-zephyr-eabi/bin", 22 | //"armToolchainPath": "${env:GNUARMEMB_TOOLCHAIN_PATH}/bin", 23 | "configFiles": [ 24 | "zephyr/boards/arm/nucleo_f103rb/support/openocd.cfg" 25 | ] 26 | }, 27 | { 28 | "name": "zephyr STM32F446ZE", 29 | "type": "cortex-debug", 30 | "request": "launch", 31 | "servertype": "openocd", 32 | "runToEntryPoint": "main", 33 | "cwd": "${workspaceRoot}", 34 | "executable": "build/zephyr/zephyr.elf", 35 | "device": "stm32f446ze", 36 | //"interface": "swd", 37 | //"armToolchainPath": "${HOME}/zephyr-sdk-0.14.2/arm-zephyr-eabi/bin", 38 | //"armToolchainPath": "${env:GNUARMEMB_TOOLCHAIN_PATH}/bin", 39 | "configFiles": [ 40 | "zephyr/boards/arm/nucleo_f446ze/support/openocd.cfg" 41 | ] 42 | }, 43 | 44 | { 45 | // build task before debugging 46 | "preLaunchTask": "Build TMC UART sample", 47 | 48 | "name": "TMC-UART", 49 | "type": "cortex-debug", 50 | "request": "launch", 51 | "servertype": "openocd", 52 | "runToEntryPoint": "main", 53 | "cwd": "${workspaceRoot}", 54 | "executable": "build/zephyr/zephyr.elf", 55 | "device": "stm32f103rb", 56 | //"interface": "swd", 57 | //"armToolchainPath": "${HOME}/zephyr-sdk-0.14.2/arm-zephyr-eabi/bin", 58 | //"armToolchainPath": "${env:GNUARMEMB_TOOLCHAIN_PATH}/bin", 59 | "configFiles": [ 60 | "zephyr/boards/arm/nucleo_f103rb/support/openocd.cfg" 61 | ], 62 | 63 | "showDevDebugOutput": "raw" 64 | }, 65 | 66 | /*{ 67 | "name": "application-test thingy91", 68 | // task to run for building 69 | "preLaunchTask": "Build thingy91_nrf9160ns app", 70 | 71 | "cwd": "${workspaceRoot}", 72 | "executable": "application-test/build/zephyr/zephyr.elf", 73 | "interface": "swd", 74 | "request": "launch", 75 | "type": "cortex-debug", 76 | "servertype": "jlink", 77 | "serverpath": "/opt/SEGGER/JLink/JLinkGDBServerCLExe", 78 | "rtos": "Zephyr", 79 | "device": "nRF9160_xxAA", 80 | "boardId": "", 81 | "runToEntryPoint": "main", 82 | // TODO: no SVDs at that location 83 | "svdFile": "${env:NCS_BASE}/modules/hal/nordic/nrfx/mdk/nrf9160.svd", 84 | "showDevDebugOutput": "raw", 85 | "showDevDebugTimestamps": true, 86 | // "preLaunchCommands": [ 87 | // "file ${workspaceRoot}/nrf91_application/build/spm/zephyr/zephyr.elf", 88 | // "load", 89 | // "enable breakpoint", 90 | // "monitor reset" 91 | // ], 92 | "rttConfig": { 93 | "enabled": true, 94 | "address": "auto", 95 | "decoders": [ 96 | { 97 | "label": "Segger RTT Logs", 98 | "port": 0, 99 | "type": "console" 100 | } 101 | ] 102 | } 103 | },*/ 104 | ] 105 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | 7 | { 8 | "label": "Build printHAT v1", 9 | "type": "shell", 10 | "group": "build", 11 | "command": "west", 12 | "args": [ 13 | "build", 14 | "-p", "always", 15 | "-b", "printhat1", 16 | "${workspaceFolder}/samples/printhat1" 17 | ] 18 | }, 19 | { 20 | "label": "Build printHAT v2", 21 | "type": "shell", 22 | "group": "build", 23 | "command": "west", 24 | "args": [ 25 | "build", 26 | "-p", "always", 27 | "-b", "printhat2", 28 | "${workspaceFolder}/samples/printhat2" 29 | ] 30 | }, 31 | 32 | { 33 | "label": "Build TMC SPI+SD sample", 34 | "type": "shell", 35 | "group": "build", 36 | "command": "west", 37 | "args": [ 38 | "build", 39 | "-p", "always", 40 | "-b", "nucleo_f103rb", 41 | "${workspaceFolder}/samples/tmc-spi-sd" 42 | ] 43 | }, 44 | { 45 | "label": "Build TMC SPI sample", 46 | "type": "shell", 47 | "group": "build", 48 | "command": "west", 49 | "args": [ 50 | "build", 51 | "-p", "always", 52 | "-b", "nucleo_f103rb", 53 | "${workspaceFolder}/samples/tmc-spi" 54 | ] 55 | }, 56 | { 57 | "label": "Build TMC UART sample", 58 | "type": "shell", 59 | "group": "build", 60 | "command": "west", 61 | "args": [ 62 | "build", 63 | "-p", "always", 64 | "-b", "nucleo_f103rb", 65 | "${workspaceFolder}/samples/tmc-uart" 66 | ] 67 | }, 68 | { 69 | "label": "Build single-wire", 70 | "type": "shell", 71 | "group": "build", 72 | "command": "west", 73 | "args": [ 74 | "build", 75 | "-p", "always", 76 | "-b", "nucleo_f103rb", 77 | "${workspaceFolder}/samples/single-wire" 78 | ] 79 | }, 80 | { 81 | "label": "Build single-wire INT", 82 | "type": "shell", 83 | "group": "build", 84 | "command": "west", 85 | "args": [ 86 | "build", 87 | "-p", "always", 88 | "-b", "nucleo_f103rb", 89 | "${workspaceFolder}/samples/single-wire-irq" 90 | ] 91 | }, 92 | 93 | 94 | { 95 | "label": "Flash sample", 96 | "type": "shell", 97 | "group": "build", 98 | "command": "west", 99 | "args": [ 100 | "flash" 101 | ], 102 | }, 103 | { 104 | "label": "Debug sample", 105 | "type": "shell", 106 | "group": "build", 107 | "command": "west", 108 | "args": [ 109 | "debug", 110 | ], 111 | }, 112 | ] 113 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 Stefano Cottafavi 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | add_subdirectory(drivers) 5 | 6 | #zephyr_include_directories(include) -------------------------------------------------------------------------------- /Kconfig: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 Stefano Cottafavi 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | rsource "drivers/Kconfig" 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zephyr-trinamic 2 | Zephyr OS support for Trinamic TMC drivers 3 | 4 | ## Initialize workspace 5 | 6 | ### 1. Production module 7 | 8 | ``` 9 | west init -m https://github.com/cooked/zephyr-trinamic zephyr-trinamic 10 | # update modules 11 | cd zephyr-trinamic 12 | west update 13 | ``` 14 | 15 | ### 2. Local / Development 16 | 17 | A manifest folder is available, on top of the root west.yml, for the brave 18 | developer that wants to have the current repo folder (and not the parent) set up 19 | as the west workspace. 20 | This manifest pulls in the Zephyr source code and place it in the "rtos" folder 21 | instead of the default "zephyr" folder, to avoid overlapping with the 22 | existing zephyr folder that contains the module definition (module.yml). 23 | 24 | ``` 25 | cd 26 | west init -l manifest-devel 27 | west update 28 | ``` 29 | 30 | ## Build & Run 31 | The available samples can be built by running: 32 | 33 | ``` 34 | west build -b $BOARD samples/tmc-spi 35 | ``` 36 | 37 | Once it's built you can flash it by running: 38 | 39 | ``` 40 | west flash 41 | ``` 42 | -------------------------------------------------------------------------------- /boards/arm/printhat1/Kconfig.board: -------------------------------------------------------------------------------- 1 | # printHAT v2 board configuration 2 | 3 | # Copyright (c) 2022 Stefano Cottafavi 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | config BOARD_PRINTHAT1 7 | bool "printHAT v1 Motion Control Board" 8 | depends on SOC_STM32F103XB 9 | -------------------------------------------------------------------------------- /boards/arm/printhat1/Kconfig.defconfig: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 Stefano Cottafavi 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | if BOARD_PRINTHAT1 5 | 6 | config BOARD 7 | default "printhat1" 8 | 9 | config SPI_STM32_INTERRUPT 10 | default y 11 | depends on SPI 12 | 13 | endif # BOARD_PRINTHAT1 14 | -------------------------------------------------------------------------------- /boards/arm/printhat1/printhat1.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /dts-v1/; 8 | #include 9 | #include 10 | 11 | / { 12 | model = "Wrecklab's printHAT v1 board"; 13 | compatible = "wrecklab,printhat1"; 14 | 15 | chosen { 16 | zephyr,console = &usart1; 17 | zephyr,shell-uart = &usart1; 18 | zephyr,sram = &sram0; 19 | zephyr,flash = &flash0; 20 | }; 21 | 22 | leds { 23 | compatible = "gpio-leds"; 24 | led_0: led_0 { 25 | gpios = <&gpioa 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; 26 | }; 27 | led_1: led_1 { 28 | gpios = <&gpioa 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; 29 | }; 30 | led_2: led_2 { 31 | gpios = <&gpioa 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; 32 | }; 33 | led_3: led_3 { 34 | gpios = <&gpioa 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; 35 | }; 36 | }; 37 | 38 | // TODO: 39 | // other GPIO cwired are all pins from PC0-PC5,PC9-10 incl. 40 | // create a limit switch driver? 41 | 42 | aliases { 43 | h0 = &led_0; 44 | h1 = &led_1; 45 | f0 = &led_2; 46 | f1 = &led_3; 47 | }; 48 | }; 49 | 50 | &clk_hse { 51 | clock-frequency = ; 52 | status = "okay"; 53 | }; 54 | 55 | &pll { 56 | mul = <9>; 57 | clocks = <&clk_hse>; 58 | status = "okay"; 59 | }; 60 | 61 | &rcc { 62 | clocks = <&pll>; 63 | clock-frequency = ; 64 | ahb-prescaler = <1>; 65 | apb1-prescaler = <2>; 66 | apb2-prescaler = <1>; 67 | }; 68 | 69 | // USART1 tx: PA9 rx: PA10 --- to/from RPi 70 | &usart1 { 71 | pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; 72 | pinctrl-names = "default"; 73 | current-speed = <115200>; 74 | status = "okay"; 75 | }; 76 | 77 | &spi2 { 78 | status = "okay"; 79 | // TODO: check order is correct 80 | pinctrl-0 = <&spi2_sck_master_pb13 &spi2_miso_slave_pb14 &spi2_mosi_slave_pb15>; 81 | pinctrl-names = "default"; 82 | 83 | cs-gpios = <&gpiob 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, 84 | <&gpiob 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, 85 | <&gpiob 11 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, 86 | <&gpiob 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; 87 | 88 | s1: tmc2130_1@0 { 89 | reg = <0>; 90 | compatible = "trinamic,tmc2130"; 91 | // 4MHz internal, 8MHz external clock 92 | // TODO: seems not to work for higher speed than 1MHz 93 | spi-max-frequency = <1000000>; 94 | status = "okay"; 95 | 96 | // step_pin = <&gpioa 5 GPIO_ACTIVE_HIIGH> 97 | // dir_pin = <&gpioa 6 GPIO_ACTIVE_HIGH> 98 | 99 | // diag0_pin = <&gpiob 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> 100 | // en_pin = <&gpioa 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> 101 | }; 102 | s2: tmc2130_2@1 { 103 | reg = <1>; 104 | compatible = "trinamic,tmc2130"; 105 | spi-max-frequency = <1000000>; 106 | status = "okay"; 107 | 108 | // step_pin = <&gpioa 12 GPIO_ACTIVE_HIIGH> 109 | // dir_pin = <&gpioa 15 GPIO_ACTIVE_HIGH> 110 | 111 | // diag0_pin = <&gpiob 6 (GPIO_ACTIVE_LOW)> 112 | // en_pin = <&gpioa 11 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> 113 | }; 114 | s3: tmc2130_3@2 { 115 | reg = <2>; 116 | compatible = "trinamic,tmc2130"; 117 | spi-max-frequency = <1000000>; 118 | status = "okay"; 119 | 120 | // step_pin = <&gpioc 7 GPIO_ACTIVE_HIIGH> 121 | // dir_pin = <&gpioc 8 GPIO_ACTIVE_HIGH> 122 | 123 | // diag0_pin = <&gpiob 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> 124 | // en_pin = <&gpioc 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> 125 | }; 126 | s4: tmc2130_4@3 { 127 | reg = <3>; 128 | compatible = "trinamic,tmc2130"; 129 | spi-max-frequency = <1000000>; 130 | status = "okay"; 131 | 132 | // step_pin = <&gpioc 14 GPIO_ACTIVE_HIIGH> 133 | // dir_pin = <&gpioc 15 GPIO_ACTIVE_HIGH> 134 | 135 | // diag0_pin = <&gpiob 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> 136 | // en_pin = <&gpioc 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> 137 | 138 | }; 139 | }; 140 | 141 | /*&timers2 { 142 | status = "okay"; 143 | 144 | pwm2: pwm { 145 | status = "okay"; 146 | pinctrl-0 = <&tim2_ch1_pa5>; 147 | pinctrl-names = "default"; 148 | }; 149 | };*/ 150 | 151 | /*&adc1 { 152 | pinctrl-0 = <&adc1_in0_pa0>; 153 | pinctrl-names = "default"; 154 | status = "okay"; 155 | };*/ 156 | 157 | &flash0 { 158 | partitions { 159 | compatible = "fixed-partitions"; 160 | #address-cells = <1>; 161 | #size-cells = <1>; 162 | 163 | /* Set 2KB of storage at the end of 128KB flash */ 164 | storage_partition: partition@1f800 { 165 | label = "storage"; 166 | reg = <0x0001f800 DT_SIZE_K(2)>; 167 | }; 168 | }; 169 | }; 170 | -------------------------------------------------------------------------------- /boards/arm/printhat1/printhat1_defconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | CONFIG_SOC_SERIES_STM32F1X=y 4 | CONFIG_SOC_STM32F103XB=y 5 | 6 | # enable uart driver 7 | CONFIG_SERIAL=y 8 | # enable console 9 | CONFIG_CONSOLE=y 10 | CONFIG_UART_CONSOLE=y 11 | 12 | # enable GPIO 13 | CONFIG_GPIO=y 14 | 15 | # enable clock 16 | CONFIG_CLOCK_CONTROL=y 17 | 18 | # enable pin controller 19 | CONFIG_PINCTRL=y 20 | -------------------------------------------------------------------------------- /boards/arm/printhat2/Kconfig.board: -------------------------------------------------------------------------------- 1 | # printHAT v2 board configuration 2 | 3 | # Copyright (c) 2022 Stefano Cottafavi 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | config BOARD_PRINTHAT2 7 | bool "printHAT v2 Motion Control Board" 8 | depends on SOC_STM32F401XE 9 | -------------------------------------------------------------------------------- /boards/arm/printhat2/Kconfig.defconfig: -------------------------------------------------------------------------------- 1 | # NUCLEO-64 F401RE board configuration 2 | 3 | # Copyright (c) 2022 Stefano Cottafavi 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | if BOARD_PRINTHAT2 7 | 8 | config BOARD 9 | default "printhat2" 10 | 11 | config SPI_STM32_INTERRUPT 12 | default y 13 | depends on SPI 14 | 15 | endif # BOARD_PRINTHAT2 16 | -------------------------------------------------------------------------------- /boards/arm/printhat2/printhat2.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /dts-v1/; 8 | #include 9 | #include 10 | 11 | / { 12 | model = "Wrecklab's printHAT v2 board"; 13 | compatible = "wrecklab,printhat2"; 14 | 15 | chosen { 16 | //zephyr,console = &usart1; 17 | //zephyr,shell-uart = &usart1; 18 | zephyr,console = &cdc_acm_uart0; 19 | //zephyr,shell-uart = &cdc_acm_uart0; 20 | zephyr,sram = &sram0; 21 | zephyr,flash = &flash0; 22 | zephyr,code-partition = &slot0_partition; 23 | }; 24 | 25 | leds { 26 | compatible = "gpio-leds"; 27 | led_0:led_0 { 28 | gpios = <&gpioc 0 GPIO_ACTIVE_LOW>; 29 | }; 30 | led_1:led_1 { 31 | gpios = <&gpioc 1 GPIO_ACTIVE_LOW>; 32 | }; 33 | led_2:led_2 { 34 | gpios = <&gpioc 2 GPIO_ACTIVE_LOW>; 35 | }; 36 | led_3:led_3 { 37 | gpios = <&gpioc 3 GPIO_ACTIVE_LOW>; 38 | }; 39 | led_4:led_4 { 40 | gpios = <&gpioc 4 GPIO_ACTIVE_LOW>; 41 | }; 42 | 43 | gp4:gp4 { 44 | gpios = <&gpioa 4 GPIO_ACTIVE_HIGH>; 45 | }; 46 | }; 47 | 48 | aliases { 49 | h0 = &led_0; 50 | h1 = &led_1; 51 | h2 = &led_2; 52 | f0 = &led_3; 53 | f1 = &led_4; 54 | }; 55 | }; 56 | 57 | &clk_hse { 58 | clock-frequency = ; 59 | status = "okay"; 60 | }; 61 | 62 | &pll { 63 | div-m = <8>; 64 | mul-n = <336>; 65 | div-p = <4>; 66 | div-q = <7>; 67 | clocks = <&clk_hse>; 68 | status = "okay"; 69 | }; 70 | 71 | &rcc { 72 | clocks = <&pll>; 73 | clock-frequency = ; 74 | ahb-prescaler = <1>; 75 | apb1-prescaler = <2>; 76 | apb2-prescaler = <1>; 77 | }; 78 | 79 | &timers1 { 80 | status = "okay"; 81 | st,prescaler = <100>; 82 | stepper0: pwm { 83 | status = "okay"; 84 | pinctrl-0 = < &tim1_ch1_pwm_pa8 >; 85 | pinctrl-names = "default"; 86 | }; 87 | }; 88 | 89 | 90 | 91 | // USART1 tx:PA9 rx:PA10 --- to/from RPi 92 | // USART2 tx:PA2 rx:PA3 --- UART1, mot X,Y,Z 93 | // USART6 tx:PC6 rx:PC7 --- UART2, mot E0,E1 94 | &usart1 { 95 | pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; 96 | pinctrl-names = "default"; 97 | current-speed = <115200>; 98 | status = "okay"; 99 | }; 100 | 101 | &usart2 { 102 | status = "okay"; 103 | single-wire; 104 | 105 | pinctrl-0 = <&usart2_tx_pa2>; 106 | pinctrl-names = "default"; 107 | current-speed = <115200>; 108 | 109 | /*dmas = <&dma1 6 4 0x28440 0x03>, // Stream 6, Channel 4, ... 110 | <&dma1 5 4 0x28480 0x03>; // Stream 5, Channel 4, ... 111 | dma-names = "tx", "rx"; 112 | */ 113 | 114 | // TODO: 115 | s1:tmc2209_1 { 116 | compatible = "trinamic,tmc2209"; 117 | status = "okay"; 118 | slaveaddr = <0>; 119 | en-gpios = <&gpiob 3 GPIO_ACTIVE_LOW>; 120 | // step/dir 121 | pwms = <&stepper0 1 10000 PWM_POLARITY_NORMAL>; 122 | dir-gpios = <&gpioc 7 GPIO_ACTIVE_HIGH>; 123 | }; 124 | s2:tmc2209_2 { 125 | compatible = "trinamic,tmc2209"; 126 | status = "okay"; 127 | slaveaddr = <1>; 128 | en-gpios = <&gpioa 13 GPIO_ACTIVE_LOW>; 129 | // step/dir 130 | pwms = <&stepper0 1 10000 PWM_POLARITY_NORMAL>; 131 | dir-gpios = <&gpioc 7 GPIO_ACTIVE_HIGH>; 132 | }; 133 | s3:tmc2209_3 { 134 | compatible = "trinamic,tmc2209"; 135 | status = "okay"; 136 | slaveaddr = <2>; 137 | en-gpios = <&gpiob 9 GPIO_ACTIVE_LOW>; 138 | // step/dir 139 | pwms = <&stepper0 1 10000 PWM_POLARITY_NORMAL>; 140 | dir-gpios = <&gpioc 7 GPIO_ACTIVE_HIGH>; 141 | }; 142 | 143 | }; 144 | 145 | &usart6 { 146 | status = "okay"; 147 | single-wire; 148 | 149 | pinctrl-0 = <&usart6_tx_pc6>; 150 | pinctrl-names = "default"; 151 | current-speed = <115200>; 152 | 153 | // see: 154 | // https://docs.zephyrproject.org/latest/build/dts/api/bindings/dma/st%2Cstm32-dma-v1.html#st-stm32-dma-v1 155 | /*dmas = <&dma2 6 5 0x28440 0x03>, // Stream 6, Channel 5, ... 156 | <&dma2 1 5 0x28480 0x03>; // Stream 1, Channel 5, ... 157 | dma-names = "tx", "rx"; 158 | */ 159 | 160 | /*tmc5160 { 161 | compatible = "trinamic,tmc5160"; 162 | status = "okay"; 163 | }; 164 | tmc5160 { 165 | compatible = "trinamic,tmc5160"; 166 | status = "okay"; 167 | }; 168 | */ 169 | 170 | }; 171 | 172 | zephyr_udc0: &usbotg_fs { 173 | pinctrl-0 = <&usb_otg_fs_dm_pa11 &usb_otg_fs_dp_pa12>; 174 | pinctrl-names = "default"; 175 | status = "okay"; 176 | 177 | cdc_acm_uart0: cdc_acm_uart0 { 178 | compatible = "zephyr,cdc-acm-uart"; 179 | }; 180 | }; 181 | 182 | 183 | // see 184 | // https://github.com/zephyrproject-rtos/zephyr/blob/db3f8c16e9c95801961a433c07f481bfcb385466/tests/drivers/uart/uart_async_api/boards/nucleo_f103rb.overlay 185 | /*&dma1 { 186 | status = "okay"; 187 | }; 188 | &dma2 { 189 | status = "okay"; 190 | };*/ 191 | 192 | /*&adc1 { 193 | pinctrl-0 = <&adc1_in0_pa0>; 194 | pinctrl-names = "default"; 195 | status = "okay"; 196 | };*/ 197 | 198 | 199 | &flash0 { 200 | 201 | partitions { 202 | compatible = "fixed-partitions"; 203 | #address-cells = <1>; 204 | #size-cells = <1>; 205 | 206 | boot_partition: partition@0 { 207 | label = "mcuboot"; 208 | reg = <0x00000000 0x00010000>; 209 | read-only; 210 | }; 211 | 212 | /* 213 | * The flash starting at offset 0x10000 and ending at 214 | * offset 0x1ffff is reserved for use by the application. 215 | */ 216 | 217 | slot0_partition: partition@20000 { 218 | label = "image-0"; 219 | reg = <0x00020000 0x00020000>; 220 | }; 221 | slot1_partition: partition@40000 { 222 | label = "image-1"; 223 | reg = <0x00040000 0x00020000>; 224 | }; 225 | scratch_partition: partition@60000 { 226 | label = "image-scratch"; 227 | reg = <0x00060000 0x00020000>; 228 | }; 229 | }; 230 | }; 231 | -------------------------------------------------------------------------------- /boards/arm/printhat2/printhat2_defconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | CONFIG_SOC_SERIES_STM32F4X=y 4 | CONFIG_SOC_STM32F401XC=y 5 | 6 | # Enable MPU 7 | CONFIG_ARM_MPU=y 8 | 9 | # Enable HW stack protection 10 | CONFIG_HW_STACK_PROTECTION=y 11 | 12 | # Serial Drivers 13 | CONFIG_SERIAL=y 14 | CONFIG_UART_INTERRUPT_DRIVEN=y 15 | CONFIG_CONSOLE=y 16 | CONFIG_UART_CONSOLE=y 17 | 18 | # enable GPIO 19 | CONFIG_GPIO=y 20 | 21 | # clock configuration 22 | CONFIG_CLOCK_CONTROL=y 23 | 24 | # enable pin controller 25 | CONFIG_PINCTRL=y 26 | -------------------------------------------------------------------------------- /clear-west.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm -rf .west 3 | rm -rf build 4 | rm -rf rtos 5 | rm -rf modules 6 | rm -rf bootloader 7 | -------------------------------------------------------------------------------- /drivers/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(tmc) 2 | add_subdirectory_ifdef(CONFIG_TMC2130 tmc2130) 3 | add_subdirectory_ifdef(CONFIG_TMC2209 tmc2209) 4 | add_subdirectory_ifdef(CONFIG_TMC5160 tmc5160) 5 | -------------------------------------------------------------------------------- /drivers/Kconfig: -------------------------------------------------------------------------------- 1 | menu "TRINAMIC drivers" 2 | 3 | config TMC_SD 4 | bool "Use STEP/DIR mode" 5 | 6 | config TMC_SPI 7 | bool "Use SPI" 8 | 9 | config TMC_UART 10 | bool "Use UART" 11 | 12 | rsource "tmc2130/Kconfig" 13 | rsource "tmc2209/Kconfig" 14 | rsource "tmc5160/Kconfig" 15 | 16 | endmenu -------------------------------------------------------------------------------- /drivers/tmc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | # Add *.h to global include paths 6 | zephyr_include_directories(.) 7 | 8 | zephyr_library() 9 | 10 | zephyr_library_sources(tmc.c) 11 | zephyr_library_sources_ifdef(CONFIG_TMC_SPI tmc_spi.c) 12 | zephyr_library_sources_ifdef(CONFIG_TMC_UART tmc_uart.c) 13 | zephyr_library_sources_ifdef(CONFIG_SHELL tmc_shell.c) 14 | -------------------------------------------------------------------------------- /drivers/tmc/tmc.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2022 Stefano Cottafavi . 3 | * SPDX-License-Identifier: GPL-2.0-only 4 | */ 5 | 6 | #include "tmc.h" 7 | 8 | attr get_field(char *key, struct field *fields) { 9 | int i = 0; 10 | char *name = fields[i].name; 11 | while (name) { 12 | if (strcmp(name, key) == 0) 13 | return fields[i].a; 14 | name = fields[++i].name; 15 | } 16 | 17 | // not found 18 | attr na = {0,0,0}; 19 | return na; 20 | } 21 | -------------------------------------------------------------------------------- /drivers/tmc/tmc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef ZEPHYR_DRIVERS_TMC_H_ 8 | #define ZEPHYR_DRIVERS_TMC_H_ 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #ifdef CONFIG_TMC_SPI 16 | #include 17 | #endif 18 | 19 | #ifdef CONFIG_TMC_UART 20 | #include 21 | #endif 22 | 23 | // common config 24 | #define DEFAULT_USTEP 256 // [-] 25 | #define DEFAULT_STEPS_TURN 200 * DEFAULT_USTEP 26 | #define RPM_TO_PPS DEFAULT_STEPS_TURN / 60.0f 27 | #define DEFAULT_ROT_DIS 1000 // [mm] 28 | 29 | // driver structs 30 | struct tmc_data { 31 | uint16_t r_sens; 32 | uint16_t i_run; 33 | uint16_t i_hold; 34 | 35 | #if CONFIG_TMC_UART 36 | 37 | // async 38 | uint8_t tx_buf[8]; 39 | uint8_t rx_buf[8]; 40 | 41 | uint8_t rd_data[16]; 42 | uint32_t data; // Register data (payload in response message) 43 | 44 | uint8_t tx_bytes; // transferred bytes 45 | uint8_t xfer_bytes; // transferred bytes 46 | uint8_t msg_bytes; // msg length (set at runtime ) 47 | 48 | bool has_rsp; // has a response? // TODO: always true 49 | 50 | 51 | struct k_sem tx_sem; 52 | struct k_sem rx_sem; 53 | 54 | 55 | 56 | #endif 57 | 58 | }; 59 | 60 | struct tmc_config { 61 | 62 | #if CONFIG_TMC_SPI 63 | const struct spi_dt_spec spi; 64 | #endif 65 | #if CONFIG_TMC_UART 66 | const struct device *uart_dev; 67 | //uart_irq_callback_user_data_t cb; 68 | uart_callback_t cb; 69 | #endif 70 | 71 | uint8_t slave; 72 | 73 | struct pwm_dt_spec step; 74 | struct gpio_dt_spec dir; 75 | struct gpio_dt_spec en; 76 | 77 | struct gpio_dt_spec diag0_pin; 78 | struct gpio_dt_spec diag1_pin; 79 | 80 | uint8_t run_current; 81 | uint8_t hold_current; 82 | float r_sens; 83 | 84 | float rpm_to_hzs; 85 | float rotation_distance; // [mm/turn] linear distance travelled per single motor turn 86 | 87 | }; 88 | 89 | 90 | // registers/fileds mapping 91 | typedef struct attr { 92 | uint8_t reg; 93 | uint32_t mask; 94 | uint8_t shift; 95 | } attr; 96 | 97 | struct field { 98 | char *name; 99 | attr a; 100 | }; 101 | 102 | struct field_reg { 103 | char *name; // name of the reg containing the field 104 | struct field f; // 105 | }; 106 | 107 | struct reg_attr { 108 | uint8_t reg; 109 | char *rwc; 110 | }; 111 | struct reg { 112 | char *name; 113 | struct reg_attr attr; 114 | }; 115 | 116 | // 117 | // API 118 | // 119 | attr get_field(char *key, struct field *fields); 120 | 121 | uint8_t tmc_reg_read(const struct device *dev, uint8_t slave, uint8_t reg, uint32_t *data); 122 | uint8_t tmc_reg_write(const struct device *dev, uint8_t slave, uint8_t reg, uint32_t value); 123 | 124 | int32_t tmc_get(const struct device *dev, uint8_t slave, char *key); 125 | void tmc_set(const struct device *dev, uint8_t slave, char *key, int32_t value); 126 | 127 | void tmc_set_mode(const struct device *dev, uint8_t slave, uint8_t mode); 128 | // 129 | int tmc_init(const struct device *dev, uint8_t slave); 130 | void tmc_set_irun_ihold(const struct device *dev, uint8_t slave, uint8_t irun, uint8_t ihold); 131 | void tmc_run(const struct device *dev, uint8_t slave, int32_t speed, int32_t acc); 132 | int tmc_dump(const struct device *dev, uint8_t slave); 133 | int tmc_test(const struct device *dev); 134 | 135 | #endif /* ZEPHYR_DRIVERS_TMC_H_ */ 136 | -------------------------------------------------------------------------------- /drivers/tmc/tmc_shell.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | //#include 8 | #include 9 | 10 | //#include "tmc.h" 11 | #include "tmc_shell.h" 12 | 13 | extern bool toggle; 14 | extern const struct device *tmc0; 15 | 16 | //extern struct field fields[]; 17 | 18 | uint8_t slave = 0; 19 | 20 | /*static int cmd_tmc_get(const struct shell *shell, size_t argc, char *argv[]) 21 | { 22 | 23 | if(argc!=4) 24 | shell_error(shell, "Wrong number of argument."); 25 | 26 | uint32_t data; 27 | 28 | char *fname = argv[3]; 29 | attr f = get_field(fname, fields); 30 | 31 | //tmc_reg_read(tmc0, slave, f.reg, &data); 32 | 33 | shell_fprintf(shell, SHELL_NORMAL, 34 | "GET - Field '%s' (reg 0x%02X) value: %u \n", fname, f.reg, (data&f.mask)>>f.shift); 35 | 36 | return 0; 37 | } 38 | static int cmd_tmc_set(const struct shell *shell, size_t argc, char *argv[]) 39 | { 40 | if(argc!=5) 41 | shell_error(shell, "Wrong number of argument."); 42 | 43 | uint32_t data; 44 | 45 | attr f = get_field(argv[CMD_ARG_N+2], fields); 46 | 47 | // TODO: check if the register is writable 48 | 49 | int32_t val = strtol(argv[CMD_ARG_N+3], &argv[CMD_ARG_N+3], 10); 50 | 51 | //tmc_reg_read(tmc0, slave, f.reg, &data); 52 | data &= ~f.mask; 53 | data |= val< // size_t 11 | 12 | #include "tmc.h" 13 | 14 | #define CMD_ARG_N 1 15 | 16 | int cmd_tmc(const struct shell *shell, size_t argc, char *argv[]); 17 | 18 | #endif -------------------------------------------------------------------------------- /drivers/tmc/tmc_spi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | //#include 8 | #include "tmc_spi.h" 9 | 10 | int spi_read_register(const struct spi_dt_spec *bus, uint8_t reg, uint8_t *data) 11 | { 12 | // always 40bit, 1 byte address + 4byte data 13 | uint8_t tx_buf[5] = {0x7F & reg, 0, 0, 0, 0}; 14 | 15 | 16 | const struct spi_buf spi_buf_tx = { 17 | .buf = tx_buf, 18 | .len = sizeof(tx_buf), 19 | }; 20 | struct spi_buf_set tx = { 21 | .buffers = &spi_buf_tx, 22 | .count = 1, 23 | }; 24 | 25 | 26 | struct spi_buf spi_buf_rx = { 27 | .buf = data, 28 | .len = sizeof(tx_buf), 29 | }; 30 | struct spi_buf_set rx = { 31 | .buffers = &spi_buf_rx, 32 | .count = 1, 33 | }; 34 | 35 | 36 | int ret = 0; 37 | 38 | // send command (and ignore rcv) 39 | ret = spi_transceive_dt(bus, &tx, &rx); 40 | // send dummy and keep rcv (result from previous transaction) 41 | ret = spi_transceive_dt(bus, &tx, &rx); 42 | 43 | return ret; 44 | } 45 | 46 | int spi_write_register(const struct spi_dt_spec *bus, uint8_t reg, uint32_t value) 47 | { 48 | // TODO: replace with 49 | // https://docs.zephyrproject.org/3.1.0/kernel/util/index.html#c.byteswp 50 | 51 | /*uint8_t tx_buf[5]; 52 | tx_buf[0] = REG_SPI_WRITE_BIT | reg; 53 | *(uint32_t*)&tx_buf[1] = val;*/ 54 | uint8_t tx_buf[5] = { 55 | REG_SPI_WRITE_BIT | reg, 56 | value >> 24, value >> 16, value >> 8, value 57 | }; 58 | 59 | const struct spi_buf spi_buf_tx = { 60 | .buf = tx_buf, 61 | .len = sizeof(tx_buf) 62 | }; 63 | struct spi_buf_set tx = { 64 | .buffers = &spi_buf_tx, 65 | .count = 1 66 | }; 67 | 68 | int ret = 0; 69 | 70 | // send command (and ignore rcv) 71 | ret = spi_transceive_dt(bus, &tx, NULL); 72 | // send dummy and keep rcv (result from previous transaction) 73 | //ret = spi_transceive_dt(bus, &tx, &rx); 74 | 75 | return ret; 76 | } -------------------------------------------------------------------------------- /drivers/tmc/tmc_spi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef ZEPHYR_DRIVERS_TMC5160_SPI_H_ 8 | #define ZEPHYR_DRIVERS_TMC5160_SPI_H_ 9 | 10 | #include 11 | #include 12 | 13 | #define REG_SPI_READ_BIT 0x00 14 | #define REG_SPI_WRITE_BIT 0x80 15 | 16 | // TODO: generalize to to all TMC SPI drivers 17 | 18 | int spi_read_register(const struct spi_dt_spec *bus, uint8_t reg, uint8_t *data); 19 | int spi_write_register(const struct spi_dt_spec *bus, uint8_t reg, uint32_t value); 20 | 21 | #endif /* ZEPHYR_DRIVERS_TMC5160_SPI_H_ */ 22 | -------------------------------------------------------------------------------- /drivers/tmc/tmc_uart.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | // see: https://docs.zephyrproject.org/3.1.0/hardware/peripherals/uart.html 8 | 9 | #include // memcpy 10 | #include 11 | #include // sys_to_xxx() 12 | 13 | #include "tmc.h" 14 | #include "tmc_uart.h" 15 | 16 | // DMA 17 | K_SEM_DEFINE(tx_done, 1, 1); 18 | K_SEM_DEFINE(tx_aborted, 0, 1); 19 | K_SEM_DEFINE(rx_rdy, 1, 1); 20 | K_SEM_DEFINE(rx_buf_released, 1, 1); 21 | K_SEM_DEFINE(rx_disabled, 1, 1); 22 | 23 | // interrupt 24 | //K_SEM_DEFINE(tx_sem, 1, 1); 25 | //K_SEM_DEFINE(rx_sem, 1, 1); 26 | 27 | void tmc_uart_crc(uint8_t *data, uint8_t data_len) { 28 | 29 | int i,j; 30 | uint8_t *crc = data + (data_len-1); // CRC located in last byte of message 31 | uint8_t currentByte; 32 | *crc = 0; 33 | for (i=0; i<(data_len-1); i++) { // Execute for all bytes of a message 34 | currentByte = data[i]; // Retrieve a byte to be sent from Array 35 | for (j=0; j<8; j++) { 36 | if ((*crc >> 7) ^ (currentByte&0x01)) // update CRC based result of XOR operation 37 | *crc = (*crc << 1) ^ 0x07; 38 | else 39 | *crc = (*crc << 1); 40 | currentByte = currentByte >> 1; 41 | } // for CRC bit 42 | } // for message byte 43 | } 44 | 45 | int tmc_uart_crc_check(uint8_t *data) { 46 | 47 | // isolate CRC 48 | uint8_t crc; 49 | memcpy(&crc, &data[N_RSP-1], 1); 50 | 51 | // calc CRC 52 | uint8_t data_rx[N_RSP] = {0}; 53 | memcpy(data_rx, data, N_RSP-1); 54 | tmc_uart_crc(data_rx, N_RSP); 55 | 56 | if(crc != data_rx[N_RSP-1]) 57 | return -EINVAL; 58 | 59 | return 0; 60 | 61 | } 62 | 63 | void tmc_uart_flush(const struct device *uart_dev) { 64 | uint8_t c; 65 | while (uart_fifo_read(uart_dev, &c, 1) > 0) { 66 | continue; 67 | } 68 | k_sem_reset(&rx_rdy); 69 | k_sem_reset(&tx_done); 70 | } 71 | 72 | int tmc_uart_init(const struct device *dev) { 73 | 74 | const struct tmc_config *cfg = dev->config; 75 | 76 | uart_callback_set(cfg->uart_dev, cfg->cb, (void *)dev); 77 | 78 | //uart_rx_disable(cfg->uart_dev); 79 | //k_sem_take(&rx_disabled, K_MSEC(1000)); 80 | 81 | k_sem_give(&rx_disabled); 82 | k_sem_give(&rx_rdy); 83 | 84 | return 0; 85 | } 86 | 87 | int uart_read_register(const struct device *dev, uint8_t slave, uint8_t reg, uint32_t *value) { 88 | 89 | const struct tmc_config *cfg = dev->config; 90 | struct tmc_data *data = dev->data; 91 | 92 | int ret = 0; 93 | 94 | // TODO: add check on response address being 0xFF (meaning master) 95 | // TODO: add check on response checksum 96 | 97 | // ASYNC (w/ DMA) 98 | // !!! IMPORTANT: remember to config DMA in the dts, see: 99 | // https://github.com/nrfconnect/sdk-zephyr/blob/main/tests/drivers/uart/uart_async_api/src/test_uart_async.c 100 | // https://github.com/StefJar/zephyr_stm32_uart3_dma_driver/blob/master/uart3_dma.c 101 | 102 | // TX 103 | uint8_t tx_buf[N_RD] = { SYNC_NIBBLE, slave, reg, 0 }; 104 | tmc_uart_crc(tx_buf, N_RD); 105 | 106 | /* 107 | #if CONFIG_UART_ASYNC_API 108 | // DMA 109 | 110 | // NOTE: in single-wire TX and RX are tied together (internally to the MCU) 111 | // and the sent data are also "received", so make sure to read N_RSP+N_RD 112 | // bytes 113 | 114 | uart_rx_enable(cfg->uart_dev, data->rd_data, N_RSP + N_RD, 1 * USEC_PER_SEC); 115 | k_sem_take(&rx_rdy, K_MSEC(1000)); 116 | 117 | k_sem_take(&tx_done, K_MSEC(100)); 118 | uart_tx(cfg->uart_dev, tx_buf, sizeof(tx_buf), 100 * USEC_PER_MSEC); // SYS_FOREVER_US); 119 | // wait for TX complete 120 | //k_sem_take(&tx_done, K_MSEC(1000)); 121 | //k_sem_give(&tx_done); 122 | 123 | // wait RX to complete 124 | k_sem_take(&rx_rdy, K_MSEC(1000)); 125 | k_sem_give(&rx_rdy); 126 | 127 | uart_rx_disable(cfg->uart_dev); 128 | 129 | 130 | uint8_t rsp[N_RSP] = {0}; 131 | memcpy(rsp, &data->rd_data[N_RD], N_RSP); 132 | 133 | if( tmc_uart_crc_check(rsp) ) { 134 | printk( "UART CRC error\n"); 135 | return ret; 136 | } 137 | 138 | // get data 139 | memcpy(value, &rsp[N_RSP-5], 4); 140 | 141 | 142 | #elif CONFIG_UART_INTERRUPT_DRIVEN 143 | // interrupts 144 | 145 | // Make sure last command has been transferred 146 | k_sem_take(&data->tx_sem, K_FOREVER); 147 | k_sem_take(&data->rx_sem, K_FOREVER); 148 | 149 | // TX 150 | memcpy(data->tx_buf, tx_buf, 4); 151 | uart_irq_tx_enable(cfg->uart_dev); 152 | // wait TX complete 153 | if( k_sem_take(&data->rx_sem, UART_WAIT) ) { 154 | printk( "SEM RX TAKE timeout\n"); 155 | } 156 | 157 | // wait RX complete 158 | if( k_sem_take(&data->tx_sem, UART_WAIT) ) { 159 | printk( "SEM TX TAKE timeout\n"); 160 | } else { 161 | k_sem_give(&data->rx_sem); 162 | } 163 | 164 | printk(" - data %02X %02X %02X %02X %02X %02X %02X %02X \n", 165 | data->rd_data[0], data->rd_data[1], 166 | data->rd_data[2], data->rd_data[3], 167 | data->rd_data[4], data->rd_data[5], 168 | data->rd_data[6], data->rd_data[7] 169 | ); 170 | 171 | if( tmc_uart_crc_check(data->rd_data) ) { 172 | printk( "UART CRC error\n"); 173 | return ret; 174 | } 175 | 176 | k_sem_give(&data->tx_sem); 177 | k_sem_give(&data->rx_sem); 178 | //memcpy(&value, &data->rd_data[N_RSP_SHIFT], 4); 179 | 180 | #else*/ 181 | uint8_t buf; 182 | 183 | // command 184 | int i; 185 | for(i=0; iuart_dev, tx_buf[i]); 187 | while( uart_poll_in(cfg->uart_dev, &buf)) { 188 | } 189 | } 190 | 191 | // response 192 | for(i=0; iuart_dev, &data->rd_data[i])) { 194 | } 195 | } 196 | 197 | // check 198 | if( tmc_uart_crc_check(data->rd_data) ) { 199 | printk( "UART CRC error\n"); 200 | return -1; 201 | } 202 | 203 | // unpack 204 | uint32_t val = sys_get_be32(&data->rd_data[3]); 205 | memcpy(value, &val, 4); 206 | 207 | //#endif 208 | 209 | return ret; 210 | 211 | } 212 | 213 | int uart_write_register(const struct device *dev, uint8_t slave, uint8_t reg, uint32_t value) { 214 | 215 | const struct tmc_config *cfg = dev->config; 216 | struct tmc_data *data = dev->data; 217 | 218 | uint8_t tx_buf[N_WR] = { SYNC_NIBBLE, slave, REG_WRITE_BIT | reg, 219 | 0,0,0,0, 0 220 | }; 221 | sys_put_be32(value, &tx_buf[3]); 222 | tmc_uart_crc(tx_buf, N_WR); 223 | 224 | /*#if CONFIG_UART_ASYNC_API 225 | k_sem_take(&tx_done, K_FOREVER); 226 | uart_tx(cfg->uart_dev, tx_buf, sizeof(tx_buf), 100 * USEC_PER_MSEC); // SYS_FOREVER_US); 227 | // wait for TX complete 228 | k_sem_take(&tx_done, K_MSEC(1000)); 229 | k_sem_give(&tx_done); 230 | #endif*/ 231 | 232 | uint8_t buf; 233 | 234 | // send command 235 | for(int i=0; iuart_dev, tx_buf[i]); 237 | while(uart_poll_in(cfg->uart_dev, &buf)) { 238 | } 239 | } 240 | 241 | return 0; 242 | } 243 | 244 | 245 | void tmc_uart_cb(const struct device *uart_dev, void *user_data) 246 | { 247 | 248 | const struct device *dev = user_data; 249 | struct tmc_data *data = dev->data; 250 | const struct tmc_config *cfg = dev->config; 251 | 252 | if (!uart_irq_update(uart_dev)) { 253 | return; 254 | } 255 | 256 | int ret; 257 | 258 | // RECV 259 | if (uart_irq_rx_ready(uart_dev)) { 260 | data->xfer_bytes += uart_fifo_read(uart_dev, &data->rd_data[data->xfer_bytes], 261 | data->msg_bytes - data->xfer_bytes); 262 | 263 | // RX complete 264 | if (data->xfer_bytes == data->msg_bytes) { 265 | data->xfer_bytes = 0; 266 | 267 | k_sem_give(&data->tx_sem); 268 | } 269 | } 270 | 271 | // SEND 272 | /*if (uart_irq_tx_ready(uart_dev)) { 273 | ret = uart_fifo_fill(uart_dev, data->tx_buf, N_RD); 274 | //data->tx_bytes += uart_fifo_fill(uart_dev, &data->tx_buf[data->tx_bytes], 275 | // N_RD - data->tx_bytes); 276 | printk("TX bytes: %d\n", data->tx_bytes); 277 | } 278 | 279 | // SEND complete 280 | if (uart_irq_tx_complete(uart_dev)) { 281 | printk("TX complete\n"); 282 | data->tx_bytes = 0; 283 | uart_irq_tx_disable(uart_dev); 284 | k_sem_give(&data->rx_sem); 285 | }*/ 286 | 287 | } 288 | 289 | 290 | // initial TMCs discover and addressing 291 | // see DS sec 5.4 Addressing multiple slaves 292 | void uart_discover(const struct device *uart) { 293 | 294 | // TODO: workflow 295 | // - poll a register of slave 0x00 296 | // if response is correct assign slave new "next" address and set NAO 297 | // if not, discovery end...store address map in flash (via NVS?) 298 | } 299 | void uart_load_slave_map(const struct device *uart){ 300 | // TODO: 301 | //use the slave addr map stored in memory to init all the connected slaves 302 | 303 | } 304 | 305 | 306 | // DMA callback 307 | void tmc_uart_cb_dma(const struct device *uart_dev, struct uart_event *evt, void *user_data) { 308 | 309 | const struct device *dev = (const struct device *) user_data; 310 | 311 | struct tmc_data *data = dev->data; 312 | 313 | switch (evt->type) { 314 | case UART_TX_DONE: 315 | k_sem_give(&tx_done); 316 | break; 317 | case UART_RX_RDY: 318 | k_sem_give(&rx_rdy); 319 | break; 320 | case UART_RX_BUF_RELEASED: 321 | k_sem_give(&rx_buf_released); 322 | break; 323 | case UART_RX_DISABLED: 324 | k_sem_give(&rx_disabled); 325 | break; 326 | default: 327 | break; 328 | } 329 | 330 | } 331 | -------------------------------------------------------------------------------- /drivers/tmc/tmc_uart.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef ZEPHYR_DRIVERS_TMC_UART_H_ 8 | #define ZEPHYR_DRIVERS_TMC_UART_H_ 9 | 10 | #include 11 | 12 | #define SYNC_NIBBLE 0x05 13 | #define REG_WRITE_BIT 0x80 14 | 15 | #define SLAVEADDR 0x01 // 0x01 default (internal pu resistor) 16 | #define N_WR 8 17 | #define N_RD 4 18 | #define N_RSP 8 19 | 20 | // TODO:this must be tweeket according to type of comm 21 | // 3: ok for f103 nucleo using TX poll + RX interrupt 22 | #define N_RSP_SHIFT 3 23 | 24 | /* Arbitrary max duration to wait for the response */ 25 | #define UART_WAIT K_SECONDS(1) 26 | 27 | 28 | void tmc_uart_flush(const struct device *uart_dev); 29 | 30 | void tmc_uart_cb(const struct device *uart_dev, void *user_data); 31 | void tmc_uart_cb_dma(const struct device *uart_dev, struct uart_event *evt, void *user_data); 32 | 33 | int tmc_uart_init(const struct device *dev); 34 | 35 | int uart_read_register(const struct device *dev, uint8_t slave, uint8_t reg, uint32_t *value); 36 | int uart_write_register(const struct device *dev, uint8_t slave, uint8_t reg, uint32_t value); 37 | 38 | void uart_discover(const struct device *uart); 39 | void uart_load_slave_map(const struct device *uart); 40 | 41 | 42 | #endif /* ZEPHYR_DRIVERS_TMC_UART_H_ */ 43 | -------------------------------------------------------------------------------- /drivers/tmc2130/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | # Add *.h to global include paths 6 | zephyr_include_directories(src) 7 | 8 | zephyr_library() 9 | 10 | zephyr_library_sources(src/tmc2130.c) 11 | zephyr_library_sources(src/tmc2130_map.c) 12 | #zephyr_library_sources_ifdef(CONFIG_SHELL src/tmc2130_shell.c) 13 | -------------------------------------------------------------------------------- /drivers/tmc2130/Kconfig: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | menuconfig TMC2130 6 | bool "Enable support for the TMC2130 stepper driver" 7 | default y 8 | depends on DT_HAS_TRINAMIC_TMC2130_ENABLED 9 | select HAS_TMCLIB 10 | select SPI if $(dt_compat_on_bus,$(DT_COMPAT_TRINAMIC_TMC2130),spi) 11 | select TMC_SPI if $(dt_compat_on_bus,$(DT_COMPAT_TRINAMIC_TMC2130),spi) 12 | 13 | help 14 | Enable driver for TMC2130 stepper driver. 15 | 16 | if TMC2130 17 | 18 | # TODO: diag pins and others 19 | 20 | endif # TMC2130 21 | -------------------------------------------------------------------------------- /drivers/tmc2130/src/tmc2130.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | // mind include path 8 | // https://stackoverflow.com/questions/72294929/location-of-source-file-include-drivers-gpio-h 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include // sys_to_xxx() 16 | #include 17 | 18 | #include "tmc.h" 19 | #include "tmc2130.h" 20 | #include "tmc_spi.h" 21 | 22 | // piggyback on SPI log level for now 23 | #include 24 | 25 | LOG_MODULE_REGISTER(TMC2130, CONFIG_SENSOR_LOG_LEVEL); 26 | 27 | #define DT_DRV_COMPAT trinamic_tmc2130 28 | 29 | extern struct field fields[]; 30 | extern struct reg regs[]; 31 | 32 | 33 | // TODO: replace with system utils 34 | uint32_t assemble_32(uint8_t *p_data) { 35 | int i; 36 | uint32_t result = p_data[0]; 37 | for (i = 1; i < 4; i++) 38 | result = (result << 8) + p_data[i]; 39 | return result; 40 | } 41 | 42 | static int tmc2130_init(const struct device *dev) 43 | { 44 | int res = 0; 45 | 46 | #if CONFIG_TMC_SPI 47 | const struct tmc_config *cfg = dev->config; 48 | if (!spi_is_ready(&cfg->spi)) { 49 | LOG_ERR("SPI bus is not ready"); 50 | return -ENODEV; 51 | } 52 | #endif 53 | 54 | LOG_INF("tmc2130_init done"); 55 | 56 | return res; 57 | } 58 | 59 | // TMC r/w registers 60 | uint8_t tmc_reg_read(const struct device *dev, uint8_t slave, uint8_t reg, uint32_t *data) { 61 | 62 | int res = 0; 63 | 64 | #if CONFIG_TMC_SPI 65 | const struct tmc_config *cfg = dev->config; 66 | 67 | uint8_t buf[5] = {0}; 68 | spi_read_register( &(cfg->spi), reg, buf ); 69 | // TODO: replace with sys_to.... from byteorder.h 70 | //sys_be32_to_cpu(); 71 | *data = assemble_32(&buf[1]); 72 | #else 73 | LOG_INF("TMC - Read register via SPI not enabled"); 74 | #endif 75 | 76 | return res; 77 | } 78 | 79 | uint8_t tmc_reg_write(const struct device *dev, uint8_t slave, uint8_t reg, uint32_t value) { 80 | 81 | int res = 0; 82 | 83 | #if CONFIG_TMC_SPI 84 | const struct tmc_config *cfg = dev->config; 85 | spi_write_register( &(cfg->spi), reg, value); 86 | #else 87 | LOG_INF("TMC - Write register via SPI not enabled"); 88 | #endif 89 | 90 | return 0; 91 | } 92 | 93 | int tmc_init(const struct device *dev, uint8_t slave) { 94 | 95 | const struct tmc_config *cfg = dev->config; 96 | 97 | tmc_reg_write(dev, slave, TMC2130_GSTAT, 0x7 ); // clear errors 98 | //tmc_reg_write(dev, slave, TMC5160_CHOPCONF, 0x000100C3 ); // CHOPCONF: TOFF=3, HSTRT=4, HEND=1, TBL=2, CHM=0 (SpreadCycle) 99 | 100 | // write only 101 | //tmc_set_irun_ihold(dev, slave, cfg->run_current, cfg->hold_current); 102 | 103 | //tmc_reg_write(dev, slave, TMC5160_TPOWERDOWN, 0x0000000A); // TPOWERDOWN=10: Delay before power down in stand still 104 | //tmc_reg_write(dev, slave, TMC5160_GCONF, 0x00000004); // EN_PWM_MODE=1 enables StealthChop (with default PWM_CONF) 105 | //tmc_reg_write(dev, slave, TMC5160_TPWMTHRS, 0x000001F4); // TPWM_THRS=500 yields a switching velocity about 35000 = ca. 30RPM 106 | 107 | // TODO: add init from DS 108 | // see DS pag. ??? 109 | 110 | return 0; 111 | 112 | } 113 | void tmc_run(const struct device *dev, uint8_t slave, int32_t speed, int32_t acc) { 114 | 115 | //const struct tmc5160_config *cfg = dev->config; 116 | //printk( "rot_dist : %f \n", cfg->rotation_distance); 117 | //printk( "speed conv : %f, %f, %f \n", (float)speed, RPM_TO_PPS, (float)speed * RPM_TO_PPS / TMC_T); 118 | 119 | // AMAX acceleration and deceleration value in velocity mode (DS pag. 40) 120 | //if(acc!=0) 121 | // tmc_reg_write(dev, slave, TMC5160_AMAX, (uint32_t)acc ); 122 | 123 | // VMAX velocity value in velocity mode (DS pag. 40) 124 | //tmc_reg_write(dev, slave, TMC5160_VMAX, (uint32_t)((float)speed * RPM_TO_PPS / TMC_T) ); 125 | 126 | // direction 127 | if(speed>0) { 128 | // + velocity mode 129 | //tmc_reg_write(dev, slave, TMC5160_RAMPMODE, 1); 130 | } else if(speed<0) { 131 | // - velocity mode 132 | //tmc_reg_write(dev, slave, TMC5160_RAMPMODE, 2); 133 | } else { 134 | // keep existing ramp_mode, but stop motion (speed=0) 135 | } 136 | } 137 | 138 | int tmc_dump(const struct device *dev, uint8_t slave) { 139 | 140 | uint32_t data; 141 | 142 | for(uint16_t reg = 0; reg < 1; reg++) { 143 | // dump only if readable 144 | if( strchr( regs[reg].attr.rwc, 'r') ) { 145 | tmc_reg_read( dev, slave, regs[reg].attr.reg, &data); 146 | printk(" - Register (0x%02X) %s : 0x%08X \n", regs[reg].attr.reg, regs[reg].name, data); 147 | } 148 | } 149 | 150 | return 0; 151 | } 152 | 153 | // tmc register's field getter/setter 154 | int32_t tmc_get(const struct device *dev, uint8_t slave, char *key) { 155 | 156 | attr f = get_field(key, fields); 157 | 158 | uint32_t data; 159 | tmc_reg_read(dev, slave, f.reg, &data); 160 | 161 | data &= f.mask; 162 | data |= data >> f.shift; 163 | 164 | return (int32_t) data; 165 | } 166 | void tmc_set(const struct device *dev, uint8_t slave, char *key, int32_t value) { 167 | 168 | attr f = get_field(key, fields); 169 | uint32_t data; 170 | 171 | tmc_reg_read(dev, slave, f.reg, &data); 172 | data &= ~f.mask; 173 | data |= value << f.shift; 174 | tmc_reg_write(dev, slave, f.reg, data); 175 | 176 | } 177 | 178 | // general 179 | void tmc_set_irun_ihold(const struct device *dev, uint8_t slave, uint8_t irun, uint8_t ihold) { 180 | 181 | uint32_t data = ( 182 | ( (irun << TMC2130_IRUN_SHIFT)&TMC2130_IRUN_MASK) | 183 | ( (ihold << TMC2130_IHOLD_SHIFT)&TMC2130_IHOLD_MASK ) | 184 | ( (6<data; 192 | //uint8_t buf[8]; 193 | return 0; 194 | } 195 | static int tmc2130_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) 196 | { 197 | //struct tmc5160_data *data = dev->data; 198 | 199 | switch (chan) { 200 | default: 201 | return -EINVAL; 202 | } 203 | 204 | return 0; 205 | } 206 | static const struct sensor_driver_api tmc2130_api = { 207 | .sample_fetch = tmc2130_sample_fetch, 208 | .channel_get = tmc2130_channel_get, 209 | }; 210 | 211 | // TODO: 212 | // .diag0_pin = GPIO_DT_SPEC_GET_OR(diag0_pin, 0), 213 | // .bus_init = tmc_spi_init, 214 | 215 | #define TMC2130_DEFINE(inst) \ 216 | static struct tmc_data tmc_data_##inst = { \ 217 | .r_sens = DT_INST_PROP(inst, r_sens), \ 218 | .i_run = DT_INST_PROP(inst, current_run), \ 219 | .i_hold = DT_INST_PROP(inst, current_hold), \ 220 | }; \ 221 | \ 222 | static const struct tmc_config tmc_config_##inst = { \ 223 | COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ 224 | (\ 225 | .spi = SPI_DT_SPEC_INST_GET(inst, \ 226 | SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8), 0), \ 227 | ), \ 228 | ()) \ 229 | .rotation_distance = DT_INST_PROP(inst, rotation_distance), \ 230 | }; \ 231 | \ 232 | DEVICE_DT_INST_DEFINE(inst, \ 233 | tmc2130_init, \ 234 | NULL, \ 235 | &tmc_data_##inst, \ 236 | &tmc_config_##inst, \ 237 | POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ 238 | &tmc2130_api); \ 239 | 240 | DT_INST_FOREACH_STATUS_OKAY(TMC2130_DEFINE) 241 | -------------------------------------------------------------------------------- /drivers/tmc2130/src/tmc2130.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef ZEPHYR_DRIVERS_TMC2130_H_ 8 | #define ZEPHYR_DRIVERS_TMC2130_H_ 9 | 10 | #include "tmc.h" 11 | // from hal_trinamic 12 | #include "TMC2130_Register.h" 13 | #include "TMC2130_Mask_Shift.h" 14 | 15 | // NOTE: keep it up to date according to tmcXXXX_map.c 16 | #define NREG 28 17 | 18 | #define DEFAULT_FCLK 12000000.0f // [Hz] 19 | 20 | 21 | #endif /* ZEPHYR_DRIVERS_TMC2130_H_ */ 22 | -------------------------------------------------------------------------------- /drivers/tmc2130/src/tmc2130_map.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include "tmc.h" 8 | #include "tmc2130.h" 9 | 10 | struct reg regs[] = { 11 | {"GCONF", { TMC2130_GCONF, "rw" }}, 12 | {"GSTAT", { TMC2130_GSTAT, "rwc" }}, 13 | {"IHOLD_IRUN", { TMC2130_IHOLD_IRUN, "w" }}, 14 | }; 15 | 16 | // map fields 17 | struct field fields[] = { 18 | // 0x00 GCONF 19 | { "iscaleanalog",{TMC2130_GCONF, TMC2130_SHAFT_MASK, TMC2130_SHAFT_SHIFT}}, 20 | { "shaft", {TMC2130_GCONF, TMC2130_SHAFT_MASK, TMC2130_SHAFT_SHIFT}}, 21 | // TODO: complete above 22 | // 0x01 GSTAT 23 | { "reset", {TMC2130_GSTAT, TMC2130_RESET_MASK, TMC2130_RESET_SHIFT}}, 24 | { "drverr", {TMC2130_GSTAT, TMC2130_DRV_ERR_MASK, TMC2130_DRV_ERR_SHIFT}}, 25 | { "uvcp", {TMC2130_GSTAT, TMC2130_UV_CP_MASK, TMC2130_UV_CP_SHIFT}}, 26 | 27 | // 0x10 IHOLD_IRUN 28 | { "ihold", {TMC2130_IHOLD_IRUN, TMC2130_IHOLD_MASK, TMC2130_IHOLD_SHIFT}}, 29 | { "irun", {TMC2130_IHOLD_IRUN, TMC2130_IRUN_MASK, TMC2130_IRUN_SHIFT}}, 30 | { "iholddelay", {TMC2130_IHOLD_IRUN, TMC2130_IHOLDDELAY_MASK, TMC2130_IHOLDDELAY_SHIFT}}, 31 | // 0x12 TSTEP 32 | { "tstep", {TMC2130_TSTEP, TMC2130_TSTEP_MASK, TMC2130_TSTEP_SHIFT}}, 33 | 34 | // driver status 35 | { "stst", {TMC2130_DRV_STATUS, TMC2130_STST_MASK, TMC2130_STST_SHIFT}}, 36 | { "olb", {TMC2130_DRV_STATUS, TMC2130_OLB_MASK, TMC2130_OLB_SHIFT}}, 37 | { "ola", {TMC2130_DRV_STATUS, TMC2130_OLA_MASK, TMC2130_OLA_SHIFT}}, 38 | { "s2gb", {TMC2130_DRV_STATUS, TMC2130_S2GB_MASK, TMC2130_S2GB_SHIFT}}, 39 | { "s2ga", {TMC2130_DRV_STATUS, TMC2130_S2GA_MASK, TMC2130_S2GA_SHIFT}}, 40 | { "otpw", {TMC2130_DRV_STATUS, TMC2130_OTPW_MASK, TMC2130_OTPW_SHIFT}}, 41 | { "ot", {TMC2130_DRV_STATUS, TMC2130_OT_MASK, TMC2130_OT_SHIFT}}, 42 | { "stallguard", {TMC2130_DRV_STATUS, TMC2130_STALLGUARD_MASK, TMC2130_STALLGUARD_SHIFT}}, 43 | { "csactual", {TMC2130_DRV_STATUS, TMC2130_CS_ACTUAL_MASK, TMC2130_CS_ACTUAL_SHIFT}}, 44 | { "fsactive", {TMC2130_DRV_STATUS, TMC2130_FSACTIVE_MASK, TMC2130_FSACTIVE_SHIFT}}, 45 | { "sgresult", {TMC2130_DRV_STATUS, TMC2130_SG_RESULT_MASK, TMC2130_SG_RESULT_SHIFT}}, 46 | }; 47 | -------------------------------------------------------------------------------- /drivers/tmc2209/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | # Add *.h to global include paths 6 | zephyr_include_directories(src) 7 | 8 | zephyr_library() 9 | 10 | zephyr_library_sources(src/tmc2209.c) 11 | zephyr_library_sources(src/tmc2209_map.c) -------------------------------------------------------------------------------- /drivers/tmc2209/Kconfig: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | menuconfig TMC2209 6 | bool "Enable support for the TMC2209 stepper driver" 7 | default y 8 | depends on DT_HAS_TRINAMIC_TMC2209_ENABLED 9 | select HAS_TMCLIB 10 | select SERIAL if $(dt_compat_on_bus,$(DT_COMPAT_TRINAMIC_TMC2209),uart) 11 | select TMC_UART if $(dt_compat_on_bus,$(DT_COMPAT_TRINAMIC_TMC2209),uart) 12 | help 13 | Enable driver for TMC2209 stepper driver. 14 | 15 | if TMC2209 16 | 17 | # TODO: add diag pin 18 | 19 | endif # TMC2209 20 | -------------------------------------------------------------------------------- /drivers/tmc2209/src/tmc2209.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | // mind include path 8 | // https://stackoverflow.com/questions/72294929/location-of-source-file-include-drivers-gpio-h 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include // sys_to_xxx() 17 | #include 18 | 19 | #include "tmc.h" // tmc_data, tmc_config 20 | #include "tmc2209.h" 21 | 22 | #ifdef CONFIG_TMC_SD 23 | #include 24 | #endif 25 | #ifdef CONFIG_TMC_UART 26 | #include "tmc_uart.h" 27 | #endif 28 | 29 | #include 30 | 31 | LOG_MODULE_REGISTER(TMC2209, CONFIG_SENSOR_LOG_LEVEL); 32 | 33 | 34 | #define DT_DRV_COMPAT trinamic_tmc2209 35 | 36 | extern struct field fields[]; 37 | extern struct reg regs[]; 38 | 39 | 40 | static int tmc2209_init(const struct device *dev) { 41 | 42 | //struct tmc_data *data = dev->data; 43 | const struct tmc_config *cfg = dev->config; 44 | 45 | #if CONFIG_TMC_UART 46 | 47 | LOG_DBG("TMC UART poll-mode \n"); 48 | //tmc_uart_init(dev); 49 | 50 | #endif 51 | 52 | // disable stepper 53 | //gpio_pin_configure_dt(&cfg->en, GPIO_OUTPUT_INACTIVE); 54 | gpio_pin_configure_dt(&cfg->en, GPIO_OUTPUT_ACTIVE); 55 | 56 | LOG_DBG("tmc2209_init done"); 57 | 58 | return 0; 59 | } 60 | 61 | // TMC r/w registers 62 | uint8_t tmc_reg_read(const struct device *dev, uint8_t slave, uint8_t reg, uint32_t *data) { 63 | 64 | const struct tmc_config *cfg = dev->config; 65 | #if CONFIG_TMC_UART 66 | uart_read_register(dev, cfg->slave, reg, data); 67 | #endif 68 | return 0; 69 | } 70 | 71 | uint8_t tmc_reg_write(const struct device *dev, uint8_t slave, uint8_t reg, uint32_t value) { 72 | 73 | const struct tmc_config *cfg = dev->config; 74 | #if CONFIG_TMC_UART 75 | uart_write_register( dev, cfg->slave, reg, value ); 76 | #endif 77 | return 0; 78 | } 79 | 80 | 81 | int tmc_init(const struct device *dev, uint8_t slave) { 82 | 83 | const struct tmc_config *cfg = dev->config; 84 | 85 | tmc_reg_write(dev, slave, TMC2209_GSTAT, 0x7 ); // clear errors 86 | 87 | tmc_reg_write(dev, slave, TMC2209_CHOPCONF, 0x000100C3 ); // CHOPCONF: TOFF=3, HSTRT=4, HEND=1, TBL=2, CHM=0 (SpreadCycle) 88 | tmc_set_irun_ihold(dev, slave, cfg->run_current, cfg->hold_current); // write only 89 | 90 | tmc_reg_write(dev, slave, TMC2209_TPOWERDOWN, 0x0000000A); // TPOWERDOWN=10: Delay before power down in stand still 91 | tmc_reg_write(dev, slave, TMC2209_GCONF, 0x00000004); // EN_PWM_MODE=1 enables StealthChop (with default PWM_CONF) 92 | tmc_reg_write(dev, slave, TMC2209_TPWMTHRS, 0x000001F4); // TPWM_THRS=500 yields a switching velocity about 35000 = ca. 30RPM 93 | 94 | return 0; 95 | 96 | } 97 | 98 | /*void tmc_enable() { 99 | 100 | }*/ 101 | 102 | void tmc_run(const struct device *dev, uint8_t slave, int32_t speed, int32_t acc) { 103 | 104 | #if CONFIG_TMC_SD 105 | 106 | struct tmc_config *cfg = dev->config; 107 | uint32_t period_ns = 1e9 / ( abs(speed) * RPM_TO_PPS); 108 | 109 | if(speed>0) { 110 | gpio_pin_set_dt(&cfg->dir,0); 111 | pwm_set_dt(&cfg->step, period_ns, (uint32_t)(period_ns/2)); 112 | } else if(speed<0) { 113 | gpio_pin_set_dt(&cfg->dir,1); 114 | pwm_set_dt(&cfg->step, period_ns, (uint32_t)(period_ns/2)); 115 | } else { 116 | pwm_set_pulse_dt(&cfg->step, 0); 117 | } 118 | 119 | #else 120 | // TODO: implement writing to register VACTUAL 121 | 122 | #endif 123 | 124 | } 125 | 126 | int tmc_dump(const struct device *dev, uint8_t slave) { 127 | 128 | uint32_t data; 129 | 130 | for(uint16_t reg = 0; reg < NREG; reg++) { 131 | // dump only if readable 132 | if( strchr( regs[reg].attr.rwc, 'r') ) { 133 | tmc_reg_read( dev, slave, regs[reg].attr.reg, &data); 134 | printk(" - Register (0x%02X) %s : 0x%08X \n", regs[reg].attr.reg, regs[reg].name, data); 135 | } 136 | } 137 | 138 | return 0; 139 | } 140 | 141 | // tmc register's field getter/setter 142 | int32_t tmc_get(const struct device *dev, uint8_t slave, char *key) { 143 | 144 | attr f = get_field(key, fields); 145 | 146 | uint32_t data; 147 | tmc_reg_read(dev, slave, f.reg, &data); 148 | 149 | data &= f.mask; 150 | data |= data >> f.shift; 151 | 152 | return (int32_t) data; 153 | } 154 | void tmc_set(const struct device *dev, uint8_t slave, char *key, int32_t value) { 155 | 156 | attr f = get_field(key, fields); 157 | uint32_t data; 158 | 159 | tmc_reg_read(dev, slave, f.reg, &data); 160 | data &= ~f.mask; 161 | data |= value << f.shift; 162 | tmc_reg_write(dev, slave, f.reg, data); 163 | 164 | } 165 | 166 | // general 167 | void tmc_set_irun_ihold(const struct device *dev, uint8_t slave, uint8_t irun, uint8_t ihold) { 168 | 169 | uint32_t data = ( 170 | ( (irun << TMC2209_IRUN_SHIFT)&TMC2209_IRUN_MASK) | 171 | ( (ihold << TMC2209_IHOLD_SHIFT)&TMC2209_IHOLD_MASK ) | 172 | ( (6<data; 181 | //uint8_t buf[8]; 182 | return 0; 183 | } 184 | static int tmc2209_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { 185 | //struct tmc5160_data *data = dev->data; 186 | switch (chan) { 187 | default: 188 | return -EINVAL; 189 | } 190 | return 0; 191 | } 192 | 193 | static const struct sensor_driver_api tmc2209_api = { 194 | .sample_fetch = tmc2209_sample_fetch, 195 | .channel_get = tmc2209_channel_get 196 | }; 197 | 198 | 199 | 200 | #define TMC2209_DEFINE(inst) \ 201 | static struct tmc_data tmc_data_##inst = { \ 202 | .r_sens = DT_INST_PROP(inst, r_sens), \ 203 | .i_run = DT_INST_PROP(inst, current_run), \ 204 | .i_hold = DT_INST_PROP(inst, current_hold), \ 205 | }; \ 206 | \ 207 | static const struct tmc_config tmc_config_##inst = { \ 208 | COND_CODE_1(DT_INST_ON_BUS(inst, uart), \ 209 | ( \ 210 | .uart_dev = DEVICE_DT_GET(DT_INST_BUS(inst)), \ 211 | .cb = tmc_uart_cb_dma, \ 212 | ), \ 213 | ()) \ 214 | .rotation_distance = DT_INST_PROP_OR(inst, rotation_distance, 0), \ 215 | .slave = DT_INST_PROP(inst, slaveaddr), \ 216 | .step = PWM_DT_SPEC_INST_GET_BY_IDX_OR(inst, 0, NULL), \ 217 | .dir = GPIO_DT_SPEC_INST_GET_OR(inst, dir_gpios, 0), \ 218 | .en = GPIO_DT_SPEC_INST_GET_OR(inst, en_gpios, NULL), \ 219 | .diag0_pin = GPIO_DT_SPEC_INST_GET_OR(inst, diag0_pin, 0), \ 220 | .diag1_pin = GPIO_DT_SPEC_INST_GET_OR(inst, diag1_pin, 0), \ 221 | }; \ 222 | \ 223 | DEVICE_DT_INST_DEFINE( \ 224 | inst, \ 225 | tmc2209_init, \ 226 | NULL, \ 227 | &tmc_data_##inst, \ 228 | &tmc_config_##inst, \ 229 | POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ 230 | &tmc2209_api); 231 | 232 | DT_INST_FOREACH_STATUS_OKAY(TMC2209_DEFINE) -------------------------------------------------------------------------------- /drivers/tmc2209/src/tmc2209.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef ZEPHYR_DRIVERS_TMC2209_H_ 8 | #define ZEPHYR_DRIVERS_TMC2209_H_ 9 | 10 | #include "tmc.h" 11 | // from hal_trinamic 12 | #include "TMC2209_Register.h" 13 | #include "TMC2209_Fields.h" 14 | 15 | #define NREG 24 16 | 17 | #endif /* ZEPHYR_DRIVERS_TMC2209_H_ */ 18 | -------------------------------------------------------------------------------- /drivers/tmc2209/src/tmc2209_map.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include "tmc.h" 8 | #include "tmc2209.h" 9 | 10 | struct reg regs[] = { 11 | {"GCONF", { TMC2209_GCONF, "rw" }}, 12 | {"GSTAT", { TMC2209_GSTAT, "rwc" }}, 13 | {"IFCNT", { TMC2209_IFCNT, "r" }}, 14 | {"SLAVECONF", { TMC2209_SLAVECONF, "w" }}, 15 | {"OTP_PROG", { TMC2209_OTP_PROG, "w" }}, 16 | {"OTP_READ", { TMC2209_OTP_READ, "r" }}, 17 | {"IOIN", { TMC2209_IOIN, "r" }}, 18 | {"FACTORY_CONF",{ TMC2209_FACTORY_CONF, "rw" }}, 19 | 20 | {"IHOLD_IRUN", { TMC2209_IHOLD_IRUN, "w" }}, 21 | {"TPOWERDOWN", { TMC2209_TPOWERDOWN, "w" }}, 22 | {"TSTEP", { TMC2209_TSTEP, "r" }}, 23 | {"TPWMTHRS", { TMC2209_TPWMTHRS, "w" }}, 24 | {"TCOOLTHRS", { TMC2209_TCOOLTHRS, "w" }}, 25 | 26 | {"VACTUAL", { TMC2209_VACTUAL, "w" }}, 27 | 28 | {"SGTHRS", { TMC2209_SGTHRS, "w" }}, 29 | {"SG_RESULT", { TMC2209_SG_RESULT, "r" }}, 30 | {"COOLCONF", { TMC2209_COOLCONF, "w" }}, 31 | 32 | {"MSCNT", { TMC2209_MSCNT, "r" }}, 33 | {"MSCURACT", { TMC2209_MSCURACT, "r" }}, 34 | 35 | {"CHOPCONF", { TMC2209_CHOPCONF, "rw" }}, 36 | {"DRVSTATUS", { TMC2209_DRVSTATUS, "r" }}, 37 | {"PWMCONF", { TMC2209_PWMCONF, "rw" }}, 38 | {"PWMSCALE", { TMC2209_PWMSCALE, "r" }}, 39 | {"PWM_AUTO", { TMC2209_PWM_AUTO, "r" }}, 40 | 41 | }; 42 | 43 | // map fields 44 | struct field fields[] = { 45 | // 0x00 GCONF 46 | { "iscaleanalog",{TMC2209_GCONF, TMC2209_SHAFT_MASK, TMC2209_SHAFT_SHIFT}}, 47 | { "shaft", {TMC2209_GCONF, TMC2209_SHAFT_MASK, TMC2209_SHAFT_SHIFT}}, 48 | // TODO: complete above 49 | 50 | // 0x01 GSTAT 51 | { "reset", {TMC2209_GSTAT, TMC2209_RESET_MASK, TMC2209_RESET_SHIFT}}, 52 | { "drverr", {TMC2209_GSTAT, TMC2209_DRV_ERR_MASK, TMC2209_DRV_ERR_SHIFT}}, 53 | { "uvcp", {TMC2209_GSTAT, TMC2209_UV_CP_MASK, TMC2209_UV_CP_SHIFT}}, 54 | 55 | // 0x02 IFNCT 56 | { "ifcnt", {TMC2209_IFCNT, TMC2209_IFCNT_MASK, TMC2209_IFCNT_SHIFT}}, 57 | 58 | // 0x03 SLAVECONF 59 | { "senddelay", {TMC2209_SLAVECONF, TMC2209_SLAVECONF_MASK, TMC2209_SLAVECONF_SHIFT}}, 60 | 61 | // 0x06 IOIN 62 | { "enn", {TMC2209_IOIN, TMC2209_ENN_MASK, TMC2209_ENN_SHIFT}}, 63 | { "ms1", {TMC2209_IOIN, TMC2209_MS1_MASK, TMC2209_MS1_SHIFT}}, 64 | { "ms2", {TMC2209_IOIN, TMC2209_MS2_MASK, TMC2209_MS2_SHIFT}}, 65 | { "diag", {TMC2209_IOIN, TMC2209_DIAG_MASK, TMC2209_DIAG_SHIFT}}, 66 | { "pdn_uart", {TMC2209_IOIN, TMC2209_PDN_UART_MASK, TMC2209_PDN_UART_SHIFT}}, 67 | { "step", {TMC2209_IOIN, TMC2209_STEP_MASK, TMC2209_STEP_SHIFT}}, 68 | // TODO: missing SPREAD_EN 69 | { "dir", {TMC2209_IOIN, TMC2209_DIR_MASK, TMC2209_DIR_SHIFT}}, 70 | { "version", {TMC2209_IOIN, TMC2209_VERSION_MASK, TMC2209_VERSION_SHIFT}}, 71 | 72 | // 0x10 IHOLD_IRUN 73 | { "ihold", {TMC2209_IHOLD_IRUN, TMC2209_IHOLD_MASK, TMC2209_IHOLD_SHIFT}}, 74 | { "irun", {TMC2209_IHOLD_IRUN, TMC2209_IRUN_MASK, TMC2209_IRUN_SHIFT}}, 75 | { "iholddelay", {TMC2209_IHOLD_IRUN, TMC2209_IHOLDDELAY_MASK, TMC2209_IHOLDDELAY_SHIFT}}, 76 | 77 | // 0x12 TSTEP 78 | { "tstep", {TMC2209_TSTEP, TMC2209_TSTEP_MASK, TMC2209_TSTEP_SHIFT}}, 79 | 80 | // 0x22 SPEED 81 | { "vactual", {TMC2209_VACTUAL, TMC2209_VACTUAL_MASK, TMC2209_VACTUAL_SHIFT}}, 82 | 83 | // 0x6F DRVSTATUS 84 | { "stst", {TMC2209_DRVSTATUS, TMC2209_STST_MASK, TMC2209_STST_SHIFT}}, 85 | { "stealth", {TMC2209_DRVSTATUS, TMC2209_STEALTH_MASK, TMC2209_STEALTH_SHIFT}}, 86 | { "csactual", {TMC2209_DRVSTATUS, TMC2209_CS_ACTUAL_MASK, TMC2209_CS_ACTUAL_SHIFT}}, 87 | 88 | { "t157", {TMC2209_DRVSTATUS, TMC2209_T157_MASK, TMC2209_T157_SHIFT}}, 89 | { "t150", {TMC2209_DRVSTATUS, TMC2209_T150_MASK, TMC2209_T150_SHIFT}}, 90 | { "t143", {TMC2209_DRVSTATUS, TMC2209_T143_MASK, TMC2209_T143_SHIFT}}, 91 | { "t120", {TMC2209_DRVSTATUS, TMC2209_T120_MASK, TMC2209_T120_SHIFT}}, 92 | 93 | { "olb", {TMC2209_DRVSTATUS, TMC2209_OLB_MASK, TMC2209_OLB_SHIFT}}, 94 | { "ola", {TMC2209_DRVSTATUS, TMC2209_OLA_MASK, TMC2209_OLA_SHIFT}}, 95 | { "s2vsb", {TMC2209_DRVSTATUS, TMC2209_S2VSB_MASK, TMC2209_S2VSB_SHIFT}}, 96 | { "s2vsa", {TMC2209_DRVSTATUS, TMC2209_S2VSA_MASK, TMC2209_S2VSA_SHIFT}}, 97 | { "s2gb", {TMC2209_DRVSTATUS, TMC2209_S2GB_MASK, TMC2209_S2GB_SHIFT}}, 98 | { "s2ga", {TMC2209_DRVSTATUS, TMC2209_S2GA_MASK, TMC2209_S2GA_SHIFT}}, 99 | { "ot", {TMC2209_DRVSTATUS, TMC2209_OT_MASK, TMC2209_OT_SHIFT}}, 100 | { "otpw", {TMC2209_DRVSTATUS, TMC2209_OTPW_MASK, TMC2209_OTPW_SHIFT}}, 101 | 102 | 103 | }; 104 | -------------------------------------------------------------------------------- /drivers/tmc5160/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | # Add *.h to global include paths 6 | zephyr_include_directories(src) 7 | 8 | zephyr_library() 9 | 10 | zephyr_library_sources(src/tmc5160.c) 11 | zephyr_library_sources(src/tmc5160_map.c) 12 | zephyr_library_sources_ifdef(CONFIG_SHELL src/tmc5160_shell.c) 13 | -------------------------------------------------------------------------------- /drivers/tmc5160/Kconfig: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | menuconfig TMC5160 6 | bool "Enable support for the TMC5160 stepper driver" 7 | default y 8 | depends on DT_HAS_TRINAMIC_TMC5160_ENABLED 9 | select HAS_TMCLIB 10 | select SPI if $(dt_compat_on_bus,$(DT_COMPAT_TRINAMIC_TMC5160),spi) 11 | select TMC_SPI if $(dt_compat_on_bus,$(DT_COMPAT_TRINAMIC_TMC5160),spi) 12 | select SERIAL if $(dt_compat_on_bus,$(DT_COMPAT_TRINAMIC_TMC5160),uart) 13 | select TMC_UART if $(dt_compat_on_bus,$(DT_COMPAT_TRINAMIC_TMC5160),uart) 14 | help 15 | Enable driver for TMC5160 stepper driver. 16 | 17 | if TMC5160 18 | 19 | # TODO: add diag pin 20 | 21 | endif # TMC5160 22 | -------------------------------------------------------------------------------- /drivers/tmc5160/src/tmc5160.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | // mind include path 8 | // https://stackoverflow.com/questions/72294929/location-of-source-file-include-drivers-gpio-h 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include // sys_to_xxx() 18 | #include 19 | 20 | #include "tmc.h" 21 | #include "tmc5160.h" 22 | 23 | #ifdef CONFIG_TMC_SD 24 | #include 25 | #endif 26 | #ifdef CONFIG_TMC_SPI 27 | #include "tmc_spi.h" 28 | #endif 29 | #ifdef CONFIG_TMC_UART 30 | #include "tmc_uart.h" 31 | #endif 32 | 33 | #include 34 | 35 | LOG_MODULE_REGISTER(TMC5160, CONFIG_SENSOR_LOG_LEVEL); 36 | 37 | #define DT_DRV_COMPAT trinamic_tmc5160 38 | 39 | extern struct field fields[]; 40 | extern struct reg regs[]; 41 | 42 | int tmc_test_ramp_speed(const struct device *dev, uint8_t slave) { 43 | 44 | // see DS p.116 Getting Started 45 | 46 | const struct tmc_config *cfg = dev->config; 47 | 48 | tmc_reg_write(dev, slave, TMC5160_GSTAT, 0x7 ); // clear errors 49 | tmc_reg_write(dev, slave, TMC5160_CHOPCONF, 0x000100C5 ); // CHOPCONF: TOFF=3, HSTRT=4, HEND=1, TBL=2, CHM=0 (SpreadCycle) 50 | 51 | tmc_set_irun_ihold(dev, slave, cfg->run_current, cfg->hold_current); // write only 52 | 53 | tmc_reg_write(dev, slave, TMC5160_AMAX, 5000); 54 | tmc_reg_write(dev, slave, TMC5160_VMAX, 20000); 55 | 56 | tmc_reg_write(dev, slave, TMC5160_RAMPMODE, 1); // pos velocity mode 57 | 58 | return 0; 59 | 60 | } 61 | 62 | static int tmc5160_init(const struct device *dev) 63 | { 64 | struct tmc_data *data = dev->data; 65 | const struct tmc_config *cfg = dev->config; 66 | 67 | int res = 0; 68 | 69 | LOG_DBG("TMC5160 INIT"); 70 | 71 | #if CONFIG_TMC_SD 72 | res = gpio_pin_configure_dt(&cfg->dir, GPIO_OUTPUT); 73 | if (res != 0) { 74 | printk("Error %d: failed to configure dir pin\n", res); 75 | return res; 76 | } 77 | #endif 78 | 79 | #if CONFIG_TMC_SPI 80 | if (!spi_is_ready(&cfg->spi)) { 81 | LOG_ERR("SPI bus is not ready"); 82 | return -ENODEV; 83 | } 84 | 85 | tmc_init(dev, 0); 86 | 87 | #elif CONFIG_TMC_UART 88 | 89 | #if CONFIG_UART_INTERRUPT_DRIVEN 90 | 91 | LOG_DBG("TMC UART irq-mode \n"); 92 | 93 | uart_irq_rx_disable(cfg->uart_dev); 94 | uart_irq_tx_disable(cfg->uart_dev); 95 | 96 | tmc_uart_flush(cfg->uart_dev); 97 | 98 | //uart_irq_callback_user_data_set(cfg->uart_dev, cfg->cb, (void *)dev); 99 | 100 | k_sem_init(&data->rx_sem, 1, 1); 101 | k_sem_init(&data->tx_sem, 1, 1); 102 | 103 | data->xfer_bytes = 0; 104 | 105 | uart_irq_rx_enable(cfg->uart_dev); 106 | 107 | #elif CONFIG_UART_ASYNC_API 108 | 109 | LOG_DBG("TMC UART dma-mode \n"); 110 | //tmc_uart_init(dev); 111 | 112 | #else 113 | 114 | LOG_DBG("TMC UART poll-mode \n"); 115 | //tmc_uart_init(dev); 116 | 117 | #endif 118 | 119 | // TODO: here we should initialize all slave... maybe with the addressing 120 | // first 121 | //tmc_init(dev, 0); 122 | tmc_test_ramp_speed(dev, 0); 123 | 124 | #endif 125 | 126 | LOG_DBG("tmc5160_init done"); 127 | 128 | return res; 129 | } 130 | 131 | // TMC r/w registers 132 | uint8_t tmc_reg_read(const struct device *dev, uint8_t slave, uint8_t reg, uint32_t *data) { 133 | 134 | const struct tmc_config *cfg = dev->config; 135 | 136 | #if CONFIG_TMC_SPI 137 | uint8_t buf[5] = {0}; 138 | spi_read_register( &(cfg->spi), reg, buf ); 139 | //*data = assemble_32(&buf[1]); 140 | *data = sys_get_be32(&buf[1]); 141 | #elif CONFIG_TMC_UART 142 | uart_read_register(dev, slave, reg, data); 143 | #endif 144 | 145 | return 0; 146 | } 147 | uint8_t tmc_reg_write(const struct device *dev, uint8_t slave, uint8_t reg, uint32_t value) { 148 | 149 | const struct tmc_config *cfg = dev->config; 150 | 151 | #if CONFIG_TMC_SPI 152 | spi_write_register( &(cfg->spi), reg, value); 153 | #elif CONFIG_TMC_UART 154 | uart_write_register( dev, slave, reg, value ); 155 | #endif 156 | 157 | return 0; 158 | } 159 | 160 | int tmc_init(const struct device *dev, uint8_t slave) { 161 | 162 | const struct tmc_config *cfg = dev->config; 163 | 164 | // clear errors 165 | tmc_reg_write(dev, slave, TMC5160_GSTAT, 0x7 ); 166 | 167 | // see DS pag. 116 Getting Started 168 | tmc_reg_write(dev, slave, TMC5160_CHOPCONF, 0x000100C3 ); // CHOPCONF: TOFF=3, HSTRT=4, HEND=1, TBL=2, CHM=0 (SpreadCycle) 169 | tmc_set_irun_ihold(dev, slave, cfg->run_current, cfg->hold_current); // write only 170 | tmc_reg_write(dev, slave, TMC5160_TPOWERDOWN, 0x0000000A); // TPOWERDOWN=10: Delay before power down in stand still 171 | tmc_reg_write(dev, slave, TMC5160_GCONF, 0x00000004); // EN_PWM_MODE=1 enables StealthChop (with default PWM_CONF) 172 | tmc_reg_write(dev, slave, TMC5160_TPWMTHRS, 0x000001F4); // TPWM_THRS=500 yields a switching velocity about 35000 = ca. 30RPM 173 | 174 | #if !CONFIG_TMC_SD 175 | 176 | // prevent motion 177 | tmc_reg_write(dev, slave, TMC5160_XTARGET, 0); 178 | tmc_reg_write(dev, slave, TMC5160_XACTUAL, 0); 179 | // config ramp 180 | tmc_reg_write(dev, slave, TMC5160_A1, DEFAULT_AMAX * 2); 181 | tmc_reg_write(dev, slave, TMC5160_AMAX, DEFAULT_AMAX); 182 | tmc_reg_write(dev, slave, TMC5160_V1, DEFAULT_VMAX / 2); 183 | tmc_reg_write(dev, slave, TMC5160_VMAX, DEFAULT_VMAX); 184 | tmc_reg_write(dev, slave, TMC5160_DMAX, DEFAULT_AMAX); 185 | tmc_reg_write(dev, slave, TMC5160_D1, DEFAULT_AMAX * 2); 186 | tmc_reg_write(dev, slave, TMC5160_VSTOP, DEFAULT_VSTOP); 187 | // reset position 188 | tmc_reg_write(dev, slave, TMC5160_RAMPMODE, 0); // set position mode 189 | tmc_reg_write(dev, slave, TMC5160_RAMPSTAT, 0); // clear ramp status 190 | 191 | #endif 192 | 193 | return 0; 194 | 195 | } 196 | void tmc_run(const struct device *dev, uint8_t slave, int32_t speed, int32_t acc) { 197 | 198 | #if CONFIG_TMC_SD 199 | 200 | struct tmc_config *cfg = dev->config; 201 | uint32_t period_ns = 1e9 / ( abs(speed) * RPM_TO_PPS); 202 | 203 | if(speed>0) { 204 | gpio_pin_set_dt(&cfg->dir,0); 205 | pwm_set_dt(&cfg->step, period_ns, (uint32_t)(period_ns/2)); 206 | } else if(speed<0) { 207 | gpio_pin_set_dt(&cfg->dir,1); 208 | pwm_set_dt(&cfg->step, period_ns, (uint32_t)(period_ns/2)); 209 | } else { 210 | pwm_set_pulse_dt(&cfg->step, 0); 211 | } 212 | 213 | #else 214 | // AMAX acceleration and deceleration value in velocity mode (DS pag. 40) 215 | if(acc!=0) { 216 | tmc_reg_write(dev, slave, TMC5160_AMAX, (uint32_t)acc ); 217 | } 218 | 219 | // VMAX velocity value in velocity mode (DS pag. 40) 220 | // direction 221 | if(speed>0) { 222 | // + velocity mode 223 | tmc_reg_write(dev, slave, TMC5160_VMAX, (uint32_t)((float)speed * RPM_TO_PPS / TMC_T) ); 224 | tmc_reg_write(dev, slave, TMC5160_RAMPMODE, 1); 225 | } else if(speed<0) { 226 | // - velocity mode 227 | tmc_reg_write(dev, slave, TMC5160_VMAX, (uint32_t)((float)-speed * RPM_TO_PPS / TMC_T) ); 228 | tmc_reg_write(dev, slave, TMC5160_RAMPMODE, 2); 229 | } else { 230 | // keep existing ramp_mode, but stop motion (speed=0) 231 | tmc_reg_write(dev, slave, TMC5160_VMAX, 0 ); 232 | } 233 | 234 | #endif 235 | 236 | 237 | } 238 | 239 | int tmc_dump(const struct device *dev, uint8_t slave) { 240 | 241 | uint32_t data; 242 | 243 | for(uint16_t reg = 0; reg < NREG; reg++) { 244 | // dump only if readable 245 | if( strchr( regs[reg].attr.rwc, 'r') ) { 246 | tmc_reg_read( dev, slave, regs[reg].attr.reg, &data); 247 | printk(" - Register (0x%02X) %s : 0x%08X \n", regs[reg].attr.reg, regs[reg].name, data); 248 | } 249 | } 250 | 251 | return 0; 252 | } 253 | 254 | // tmc register's field getter/setter 255 | int32_t tmc_get(const struct device *dev, uint8_t slave, char *key) { 256 | 257 | attr f = get_field(key, fields); 258 | 259 | uint32_t data; 260 | tmc_reg_read(dev, slave, f.reg, &data); 261 | 262 | data &= f.mask; 263 | data |= data >> f.shift; 264 | 265 | return (int32_t) data; 266 | } 267 | void tmc_set(const struct device *dev, uint8_t slave, char *key, int32_t value) { 268 | 269 | attr f = get_field(key, fields); 270 | uint32_t data; 271 | 272 | tmc_reg_read(dev, slave, f.reg, &data); 273 | data &= ~f.mask; 274 | data |= value << f.shift; 275 | tmc_reg_write(dev, slave, f.reg, data); 276 | 277 | } 278 | 279 | // general 280 | void tmc_set_irun_ihold(const struct device *dev, uint8_t slave, uint8_t irun, uint8_t ihold) { 281 | 282 | uint32_t data = ( 283 | ( (irun << TMC5160_IRUN_SHIFT)&TMC5160_IRUN_MASK) | 284 | ( (ihold << TMC5160_IHOLD_SHIFT)&TMC5160_IHOLD_MASK ) | 285 | ( (6<data; 336 | //uint8_t buf[8]; 337 | 338 | return 0; 339 | } 340 | static int tmc5160_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) 341 | { 342 | //struct tmc5160_data *data = dev->data; 343 | switch (chan) { 344 | default: 345 | return -EINVAL; 346 | } 347 | return 0; 348 | } 349 | static const struct sensor_driver_api tmc5160_api = { 350 | .sample_fetch = tmc5160_sample_fetch, 351 | .channel_get = tmc5160_channel_get, 352 | }; 353 | 354 | 355 | // TODO: 356 | //.cb_dma = uart_cb_dma, 357 | 358 | #define TMC5160_DEFINE(inst) \ 359 | static struct tmc_data tmc_data_##inst = { \ 360 | .r_sens = DT_INST_PROP(inst, r_sens), \ 361 | .i_run = DT_INST_PROP(inst, current_run), \ 362 | .i_hold = DT_INST_PROP(inst, current_hold), \ 363 | }; \ 364 | \ 365 | static const struct tmc_config tmc_config_##inst = { \ 366 | COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ 367 | ( \ 368 | .spi = SPI_DT_SPEC_INST_GET(inst, \ 369 | SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8), 0), \ 370 | ), \ 371 | ()) \ 372 | COND_CODE_1(DT_INST_ON_BUS(inst, uart), \ 373 | ( \ 374 | .uart_dev = DEVICE_DT_GET(DT_INST_BUS(inst)), \ 375 | .cb = tmc_uart_cb_dma, \ 376 | ), \ 377 | ()) \ 378 | .rotation_distance = DT_INST_PROP(inst, rotation_distance), \ 379 | \ 380 | .step = PWM_DT_SPEC_INST_GET_BY_IDX_OR(inst, 0, NULL), \ 381 | .dir = GPIO_DT_SPEC_INST_GET_OR(inst, dir_gpios, 0), \ 382 | .diag0_pin = GPIO_DT_SPEC_INST_GET_OR(inst, diag0_pin, 0), \ 383 | .diag1_pin = GPIO_DT_SPEC_INST_GET_OR(inst, diag1_pin, 0), \ 384 | }; \ 385 | \ 386 | DEVICE_DT_INST_DEFINE(inst, \ 387 | tmc5160_init, \ 388 | NULL, \ 389 | &tmc_data_##inst, \ 390 | &tmc_config_##inst, \ 391 | POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ 392 | &tmc5160_api); \ 393 | 394 | DT_INST_FOREACH_STATUS_OKAY(TMC5160_DEFINE) 395 | -------------------------------------------------------------------------------- /drivers/tmc5160/src/tmc5160.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef ZEPHYR_DRIVERS_TMC5160_H_ 8 | #define ZEPHYR_DRIVERS_TMC5160_H_ 9 | 10 | #include "tmc.h" 11 | // from hal_trinamic 12 | #include "TMC5160_Register.h" 13 | #include "TMC5160_Fields.h" 14 | 15 | // NOTE: keep it up to date according to tmcXXXX_map.c 16 | #define NREG 28 17 | 18 | #define DEFAULT_FCLK 12000000.0f // [Hz] 19 | 20 | #define TMC_T ((float)(1 << 23) / DEFAULT_FCLK) 21 | #define TMC_TA2 ((float)(1 << 41) / (DEFAULT_FCLK*DEFAULT_FCLK)) 22 | 23 | #define DEFAULT_AMAX 500 // ??? 24 | #define DEFAULT_VMAX 100000 // 25 | #define DEFAULT_VSTOP 10 // 26 | 27 | //self.accel_factor = float(1 << 41) / fCLK**2 * self._microsteps / self._full_step_dist 28 | //self.accel_factor_t = float(1 << 17) / fCLK 29 | 30 | // ramp 31 | int32_t tmc_get_xtarget(const struct device *dev, uint8_t slave); 32 | void tmc_set_xtarget(const struct device *dev, uint8_t slave, int32_t target); 33 | void tmc_set_vstart(const struct device *dev, uint8_t slave, uint32_t vstart); 34 | void tmc_set_a1(const struct device *dev, uint8_t slave, uint32_t a1); 35 | void tmc_set_amax(const struct device *dev, uint8_t slave, uint32_t amax); 36 | void tmc_set_v1(const struct device *dev, uint8_t slave, uint32_t v1); 37 | void tmc_set_vmax(const struct device *dev, uint8_t slave, uint32_t vmax); 38 | void tmc_set_dmax(const struct device *dev, uint8_t slave, uint32_t dmax); 39 | void tmc_set_d1(const struct device *dev, uint8_t slave, uint32_t d1); 40 | void tmc_set_vstop(const struct device *dev, uint8_t slave, uint32_t vstop); 41 | 42 | 43 | #endif /* ZEPHYR_DRIVERS_TMC5160_H_ */ 44 | -------------------------------------------------------------------------------- /drivers/tmc5160/src/tmc5160_map.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include "tmc.h" 8 | #include "tmc5160.h" 9 | 10 | struct reg regs[] = { 11 | {"GCONF", { TMC5160_GCONF, "rw" }}, 12 | {"GSTAT", { TMC5160_GSTAT, "rwc" }}, 13 | {"IFCNT", { TMC5160_IFCNT, "r" }}, 14 | {"INP_OUT", { TMC5160_INP_OUT, "r" }}, 15 | {"SLAVECONF", { TMC5160_SLAVECONF, "w" }}, 16 | {"IHOLD_IRUN", { TMC5160_IHOLD_IRUN, "w" }}, 17 | // ramp 18 | {"RAMPMODE", { TMC5160_RAMPMODE, "rw" }}, 19 | {"XACTUAL", { TMC5160_XACTUAL, "rw" }}, 20 | {"VACTUAL", { TMC5160_VACTUAL, "r" }}, 21 | {"VSTART", { TMC5160_VSTART, "w" }}, 22 | {"A1", { TMC5160_A1, "w" }}, 23 | {"V1", { TMC5160_V1, "w" }}, 24 | {"AMAX", { TMC5160_AMAX, "w" }}, 25 | {"VMAX", { TMC5160_VMAX, "w" }}, 26 | {"DMAX", { TMC5160_DMAX, "w" }}, 27 | {"D1", { TMC5160_D1, "w" }}, 28 | {"VSTOP", { TMC5160_VSTOP, "w" }}, 29 | {"TZEROWAIT", { TMC5160_TZEROWAIT, "w" }}, 30 | {"XTARGET", { TMC5160_XTARGET, "rw" }}, 31 | {"SW_MODE", { TMC5160_SWMODE, "rw" }}, 32 | {"RAMP_STAT", { TMC5160_RAMPSTAT, "rw" }}, 33 | {"XLATCH", { TMC5160_XLATCH, "r" }}, 34 | // encoder 35 | {"ENCMODE", { TMC5160_ENCMODE, "rw" }}, 36 | {"X_ENC", { TMC5160_XENC, "rw" }}, 37 | {"ENC_CONST", { TMC5160_ENC_CONST, "w" }}, 38 | {"ENC_STATUS", { TMC5160_ENC_STATUS, "rwc" }}, 39 | {"ENC_LATCH", { TMC5160_ENC_LATCH, "r" }}, 40 | {"ENC_DEVIATION",{ TMC5160_ENC_DEVIATION,"w" }}, 41 | }; 42 | 43 | // map fields 44 | struct field fields[] = { 45 | // 0x00 GCONF 46 | { "iscaleanalog",{TMC5160_GCONF, TMC5160_SHAFT_MASK, TMC5160_SHAFT_SHIFT}}, 47 | { "shaft", {TMC5160_GCONF, TMC5160_SHAFT_MASK, TMC5160_SHAFT_SHIFT}}, 48 | // TODO: complete above 49 | // 0x01 GSTAT 50 | { "reset", {TMC5160_GSTAT, TMC5160_RESET_MASK, TMC5160_RESET_SHIFT}}, 51 | { "drverr", {TMC5160_GSTAT, TMC5160_DRV_ERR_MASK, TMC5160_DRV_ERR_SHIFT}}, 52 | { "uvcp", {TMC5160_GSTAT, TMC5160_UV_CP_MASK, TMC5160_UV_CP_SHIFT}}, 53 | // 0x02 IFNCT 54 | { "ifcnt", {TMC5160_IFCNT, TMC5160_IFCNT_MASK, TMC5160_IFCNT_SHIFT}}, 55 | // 0x03 SLAVECONF 56 | { "slaveaddr", {TMC5160_SLAVECONF, TMC5160_SLAVEADDR_MASK, TMC5160_SLAVEADDR_SHIFT}}, 57 | { "senddelay", {TMC5160_SLAVECONF, TMC5160_SENDDELAY_MASK, TMC5160_SENDDELAY_SHIFT}}, 58 | // 0x04 IOIN 59 | { "reflstep", {TMC5160_INP_OUT, TMC5160_REFL_STEP_MASK, TMC5160_REFL_STEP_SHIFT}}, 60 | { "refrdir", {TMC5160_INP_OUT, TMC5160_REFR_DIR_MASK, TMC5160_REFR_DIR_SHIFT}}, 61 | { "encbdcen", {TMC5160_INP_OUT, TMC5160_ENCB_DCEN_CFG4_MASK, TMC5160_ENCB_DCEN_CFG4_SHIFT}}, 62 | { "encadcin", {TMC5160_INP_OUT, TMC5160_ENCA_DCIN_CFG5_MASK, TMC5160_ENCA_DCIN_CFG5_SHIFT}}, 63 | //... 64 | { "version", {TMC5160_INP_OUT, TMC5160_VERSION_MASK, TMC5160_VERSION_SHIFT}}, 65 | { "uart", {TMC5160_INP_OUT, TMC5160_OUTPUT_PIN_POLARITY_MASK, TMC5160_OUTPUT_PIN_POLARITY_SHIFT}}, 66 | 67 | // 0x10 IHOLD_IRUN 68 | { "ihold", {TMC5160_IHOLD_IRUN, TMC5160_IHOLD_MASK, TMC5160_IHOLD_SHIFT}}, 69 | { "irun", {TMC5160_IHOLD_IRUN, TMC5160_IRUN_MASK, TMC5160_IRUN_SHIFT}}, 70 | { "iholddelay", {TMC5160_IHOLD_IRUN, TMC5160_IHOLDDELAY_MASK, TMC5160_IHOLDDELAY_SHIFT}}, 71 | // 0x12 TSTEP 72 | { "tstep", {TMC5160_TSTEP, TMC5160_TSTEP_MASK, TMC5160_TSTEP_SHIFT}}, 73 | // 0x20 RAMPMODE 74 | { "rampmode", {TMC5160_RAMPMODE, TMC5160_RAMPMODE_MASK, TMC5160_RAMPMODE_SHIFT}}, 75 | { "xactual", {TMC5160_XACTUAL, TMC5160_XACTUAL_MASK, TMC5160_XACTUAL_SHIFT}}, 76 | { "vactual", {TMC5160_VACTUAL, TMC5160_VACTUAL_MASK, TMC5160_VACTUAL_SHIFT}}, 77 | { "vstart", {TMC5160_VSTART, TMC5160_VSTART_MASK, TMC5160_VSTART_SHIFT}}, 78 | { "a1", {TMC5160_A1, TMC5160_A1_MASK, TMC5160_A1_SHIFT}}, 79 | { "v1", {TMC5160_V1, TMC5160_V1__MASK, TMC5160_V1__SHIFT}}, 80 | { "amax", {TMC5160_AMAX, TMC5160_AMAX_MASK, TMC5160_AMAX_SHIFT}}, 81 | { "vmax", {TMC5160_VMAX, TMC5160_VMAX_MASK, TMC5160_VMAX_SHIFT}}, 82 | { "dmax", {TMC5160_DMAX, TMC5160_DMAX_MASK, TMC5160_DMAX_SHIFT}}, 83 | { "d1", {TMC5160_D1, TMC5160_D1_MASK, TMC5160_D1_SHIFT}}, 84 | { "vstop", {TMC5160_VSTOP, TMC5160_VSTOP_MASK, TMC5160_VSTOP_SHIFT}}, 85 | { "tzerowait", {TMC5160_TZEROWAIT, TMC5160_TZEROWAIT_MASK, TMC5160_TZEROWAIT_SHIFT}}, 86 | { "xtarget", {TMC5160_XTARGET, TMC5160_XTARGET_MASK, TMC5160_XTARGET_SHIFT}}, 87 | // switch mode config 88 | { "en_softstop",{TMC5160_SWMODE, TMC5160_EN_SOFTSTOP_MASK, TMC5160_EN_SOFTSTOP_SHIFT}}, 89 | { "sg_stop", {TMC5160_SWMODE, TMC5160_SG_STOP_MASK, TMC5160_SG_STOP_SHIFT}}, 90 | // TODO: complete above 91 | 92 | // 0x35 RAMP_STAT 93 | { "statussg", {TMC5160_RAMPSTAT, TMC5160_STATUS_SG_MASK, TMC5160_STATUS_SG_SHIFT}}, 94 | 95 | // driver status 96 | { "stst", {TMC5160_DRVSTATUS, TMC5160_STST_MASK, TMC5160_STST_SHIFT}}, 97 | { "olb", {TMC5160_DRVSTATUS, TMC5160_OLB_MASK, TMC5160_OLB_SHIFT}}, 98 | { "ola", {TMC5160_DRVSTATUS, TMC5160_OLA_MASK, TMC5160_OLA_SHIFT}}, 99 | { "s2gb", {TMC5160_DRVSTATUS, TMC5160_S2GB_MASK, TMC5160_S2GB_SHIFT}}, 100 | { "s2ga", {TMC5160_DRVSTATUS, TMC5160_S2GA_MASK, TMC5160_S2GA_SHIFT}}, 101 | { "otpw", {TMC5160_DRVSTATUS, TMC5160_OTPW_MASK, TMC5160_OTPW_SHIFT}}, 102 | { "ot", {TMC5160_DRVSTATUS, TMC5160_OT_MASK, TMC5160_OT_SHIFT}}, 103 | { "stallguard", {TMC5160_DRVSTATUS, TMC5160_STALLGUARD_MASK, TMC5160_STALLGUARD_SHIFT}}, 104 | { "csactual", {TMC5160_DRVSTATUS, TMC5160_CS_ACTUAL_MASK, TMC5160_CS_ACTUAL_SHIFT}}, 105 | { "fsactive", {TMC5160_DRVSTATUS, TMC5160_FSACTIVE_MASK, TMC5160_FSACTIVE_SHIFT}}, 106 | { "stealth", {TMC5160_DRVSTATUS, TMC5160_STEALTH_MASK, TMC5160_STEALTH_SHIFT}}, 107 | { "s2vsb", {TMC5160_DRVSTATUS, TMC5160_S2VSB_MASK, TMC5160_S2VSB_SHIFT}}, 108 | { "s2vsa", {TMC5160_DRVSTATUS, TMC5160_S2VSA_MASK, TMC5160_S2VSA_SHIFT}}, 109 | { "sgresult", {TMC5160_DRVSTATUS, TMC5160_SG_RESULT_MASK, TMC5160_SG_RESULT_SHIFT}}, 110 | }; 111 | -------------------------------------------------------------------------------- /drivers/tmc5160/src/tmc5160_shell.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | //#include 8 | #include 9 | 10 | #include "tmc.h" 11 | #include "tmc_shell.h" 12 | #include "tmc5160.h" 13 | 14 | //extern bool toggle; 15 | extern const struct device *tmc0; 16 | 17 | //extern struct field fields[]; 18 | 19 | //extern uint8_t slave; 20 | 21 | static int cmd_tmc_mode(const struct shell *shell, size_t argc, char *argv[]) 22 | { 23 | uint8_t mode = (uint8_t) strtol(argv[3], &argv[3], 10); 24 | 25 | tmc_set_mode(tmc0, 0, mode); 26 | 27 | return 0; 28 | } 29 | /*static int cmd_tmc_turn(const struct shell *shell, size_t argc, char *argv[]) 30 | { 31 | 32 | slave = (uint8_t) strtol(argv[CMD_ARG_N], &argv[CMD_ARG_N], 10); 33 | 34 | // increment/decrement current position by n (float) turns 35 | int32_t acc, speed; 36 | 37 | if(argc == CMD_ARG_N+3) { 38 | acc = (int32_t) strtol( argv[CMD_ARG_N+3], &argv[CMD_ARG_N+3], 10); 39 | tmc_set_amax(tmc0, slave, acc); 40 | speed = (int32_t) strtol( argv[CMD_ARG_N+2], &argv[CMD_ARG_N+2], 10); 41 | tmc_set_vmax(tmc0, slave, speed); 42 | } else if(argc == CMD_ARG_N+2) { 43 | speed = (int32_t) strtol( argv[CMD_ARG_N+2], &argv[CMD_ARG_N+2], 10); 44 | tmc_set_vmax(tmc0, slave, speed); 45 | } 46 | 47 | //float turns = strtod(argv[1], &argv[1]); 48 | int32_t turns = (int32_t) strtol( argv[CMD_ARG_N+1], &argv[CMD_ARG_N+1], 10); 49 | 50 | int32_t steps = tmc_get_xtarget(tmc0, slave); 51 | steps += (int32_t) (turns * DEFAULT_STEPS_TURN); 52 | 53 | tmc_set_xtarget(tmc0, slave, 51200); 54 | 55 | return 0; 56 | } 57 | static int cmd_tmc_goto(const struct shell *shell, size_t argc, char *argv[]) 58 | { 59 | // rotate to absolute position [turns] 60 | 61 | //float turns = strtod(argv[1], &argv[1]); 62 | int32_t turns = (int32_t) strtol( argv[1], &argv[1], 10); 63 | 64 | int32_t steps = (int32_t) (turns * DEFAULT_STEPS_TURN); 65 | // TODO: 66 | //tmc_set_xtarget(tmc, slave, steps); 67 | 68 | return 0; 69 | }*/ 70 | 71 | 72 | /*SHELL_STATIC_SUBCMD_SET_CREATE( tmc_cmds, 73 | // set mode (ramp or velocity) 74 | SHELL_CMD_ARG(mode, NULL, "Set TMC mode of operation. ($ tmc mode <0/1> // 0:velocity 1:ramp)", 75 | cmd_tmc_mode, 2, 0), 76 | SHELL_CMD_ARG(turn, NULL, "Turn motor by n turns (1.5: increment, -1.5: decrement)", 77 | cmd_tmc_turn, 3, 2), 78 | SHELL_CMD_ARG(goto, NULL, "Move TMC to position", 79 | cmd_tmc_goto, 2, 0), 80 | SHELL_SUBCMD_SET_END 81 | );*/ 82 | 83 | static int cmd_tmc5160(const struct shell *shell, size_t argc, char *argv[]) 84 | { 85 | // if generic tmc command we're done 86 | if( cmd_tmc(shell, argc, argv)==0 ) { 87 | return 0; 88 | }; 89 | 90 | char *subcmd = argv[2]; 91 | if( strcmp(subcmd,"mode")==0 ) { 92 | return cmd_tmc_mode(shell, argc, argv); 93 | 94 | } /*else if( strcmp(subcmd,"turn")==0 ) { 95 | return cmd_tmc_turn(shell, argc, argv); 96 | 97 | } else if( strcmp(subcmd,"goto")==0 ) { 98 | return cmd_tmc_goto(shell, argc, argv); 99 | 100 | }*/ 101 | return -EINVAL; 102 | 103 | } 104 | 105 | SHELL_CMD_ARG_REGISTER(tmc, NULL, "TMC driver commands", cmd_tmc5160, 3, 99); -------------------------------------------------------------------------------- /drivers/zephyr/module.yml: -------------------------------------------------------------------------------- 1 | build: 2 | cmake: . 3 | kconfig: Kconfig 4 | settings: 5 | dts_root: .. -------------------------------------------------------------------------------- /dts/bindings/trinamic,tmc.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | properties: 6 | pwms: 7 | type: phandle-array 8 | description: | 9 | Step pin 10 | 11 | dir-gpios: 12 | type: phandle-array 13 | description: | 14 | Dir pin 15 | 16 | en-gpios: 17 | type: phandle-array 18 | description: | 19 | Enable pin 20 | 21 | diag0-pin: 22 | type: phandles 23 | description: | 24 | Diagnostic pin 0 25 | diag1-pin: 26 | type: phandles 27 | description: | 28 | Diagnostic pin 1 29 | 30 | r-sens: 31 | type: int 32 | description: | 33 | Sensing resistor [mohm] 34 | default: 110 35 | current-run: 36 | type: int 37 | description: | 38 | Operating current [1-32] 39 | default: 10 40 | current-hold: 41 | type: int 42 | description: | 43 | Holding current [1-32] 44 | default: 5 45 | 46 | rotation-distance: 47 | type: int 48 | description: | 49 | Linear displacement per motor turn [mm] 50 | default: 1000 -------------------------------------------------------------------------------- /dts/bindings/trinamic,tmc2130-spi.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | description: TMC2130 stepper driver (SPI) 6 | 7 | compatible: "trinamic,tmc2130" 8 | 9 | include: [ "spi-device.yaml", "trinamic,tmc.yml"] 10 | -------------------------------------------------------------------------------- /dts/bindings/trinamic,tmc2209-uart.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | description: TMC2209 stepper driver (UART) 6 | 7 | compatible: "trinamic,tmc2209" 8 | 9 | include: ["uart-device.yaml", "trinamic,tmc.yml"] 10 | 11 | properties: 12 | slaveaddr: 13 | type: int 14 | description: | 15 | Address of this TMC instance 16 | default: 0 -------------------------------------------------------------------------------- /dts/bindings/trinamic,tmc5160-spi.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | description: TMC5160 stepper driver (SPI) 6 | 7 | compatible: "trinamic,tmc5160" 8 | 9 | include: [ "spi-device.yaml", "trinamic,tmc.yml"] 10 | -------------------------------------------------------------------------------- /dts/bindings/trinamic,tmc5160-uart.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | description: TMC5160 stepper driver (UART) 6 | 7 | compatible: "trinamic,tmc5160" 8 | 9 | include: ["uart-device.yaml", "trinamic,tmc.yml"] 10 | -------------------------------------------------------------------------------- /manifest-devel/west.yml: -------------------------------------------------------------------------------- 1 | manifest: 2 | 3 | self: 4 | path: zephyr-trinamic 5 | 6 | remotes: 7 | - name: zephyr 8 | url-base: https://github.com/zephyrproject-rtos 9 | - name: trinamic 10 | url-base: https://github.com/cooked 11 | 12 | projects: 13 | - name: zephyr 14 | remote: zephyr 15 | revision: main 16 | path: rtos 17 | import: 18 | name-allowlist: 19 | - cmsis 20 | - hal_stm32 21 | 22 | - name: hal_tmc 23 | remote: trinamic 24 | repo-path: TMC-API 25 | path: modules/hal/tmc 26 | revision: zephyr 27 | -------------------------------------------------------------------------------- /samples/application/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | # Add the driver directory as a zephyr module by hand 4 | list(APPEND ZEPHYR_EXTRA_MODULES 5 | ${CMAKE_CURRENT_SOURCE_DIR}/../drivers/sensors/ad5423 6 | ) 7 | 8 | list(APPEND OVERLAY_CONFIG 9 | ${CMAKE_CURRENT_SOURCE_DIR}/../drivers/sensors/ad5423/ad5423.conf 10 | ) 11 | 12 | # Re-direct the directory where the 'boards' directory is found from 13 | # $ZEPHYR_BASE to this directory. 14 | #set(BOARD_ROOT ${CMAKE_CURRENT_LIST_DIR}) 15 | set(BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/..) 16 | # This sample is only compatible with our board because it has 17 | # re-directed the 'boards' directory to a directory that only contains 18 | # this board. 19 | set(BOARD letitbeat_f446ze) 20 | 21 | 22 | cmake_minimum_required(VERSION 3.20.0) 23 | 24 | # required for apps 25 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 26 | 27 | project(application_letitbeat) 28 | 29 | zephyr_include_directories(src) 30 | 31 | 32 | # Note that here, we're adding CMAKE_SOURCE_DIR to the include path for nanopb. 33 | # This is needed because the below call to nanopb_generate_cpp() is using 34 | # 'RELPATH .' 35 | set(NANOPB_OPTIONS "-I${CMAKE_SOURCE_DIR}") 36 | nanopb_generate_cpp(proto_sources proto_headers RELPATH . 37 | src/simple.proto 38 | ) 39 | # we need to be able to include generated header files 40 | zephyr_library_include_directories(${CMAKE_CURRENT_BINARY_DIR}) 41 | 42 | #FILE(GLOB app_sources src/*.c) 43 | #target_sources(app PRIVATE ${proto_sources} ${app_sources}) 44 | target_sources(app PRIVATE 45 | src/main.c 46 | src/led.c 47 | src/com.c 48 | #src/sens.c 49 | src/shell.c 50 | ) -------------------------------------------------------------------------------- /samples/application/boards/nucleo_f446ze.overlay: -------------------------------------------------------------------------------- 1 | 2 | / { 3 | chosen { 4 | zephyr,console = &cdc_acm_uart0; 5 | }; 6 | }; 7 | 8 | &zephyr_udc0 { 9 | cdc_acm_uart0: cdc_acm_uart0 { 10 | compatible = "zephyr,cdc-acm-uart"; 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /samples/application/prj.conf: -------------------------------------------------------------------------------- 1 | 2 | CONFIG_GPIO=y 3 | CONFIG_SENSOR=y 4 | CONFIG_PRINTK=y 5 | 6 | CONFIG_LOG=y 7 | CONFIG_LOG_MODE_IMMEDIATE=y 8 | CONFIG_CBPRINTF_FP_SUPPORT=y 9 | 10 | CONFIG_SHELL=y 11 | 12 | CONFIG_SERIAL=y 13 | CONFIG_CONSOLE=y 14 | 15 | # com stack 16 | CONFIG_USB_DEVICE_STACK=y 17 | CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=y 18 | #CONFIG_USB_DEVICE_PRODUCT="Zephyr Console" 19 | 20 | #CONFIG_UART_INTERRUPT_DRIVEN=y 21 | CONFIG_UART_LINE_CTRL=y 22 | 23 | # protobuf 24 | CONFIG_NANOPB=y 25 | 26 | # enable custom sensors 27 | #CONFIG_AD5423=y -------------------------------------------------------------------------------- /samples/application/src/com.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | LOG_MODULE_DECLARE(main_firmware, LOG_LEVEL_DBG); 4 | 5 | #include // sprintf() 6 | #include // strlen() 7 | #include // gmtime() 8 | 9 | #include 10 | //#include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "common.h" 17 | #include "com.h" 18 | 19 | // USB 20 | // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/samples/subsys/usb/console/README.html 21 | 22 | // protobuf 23 | //#include 24 | //#include 25 | //#include "src/simple.pb.h" 26 | 27 | extern struct k_fifo mdata_fifo; 28 | 29 | //BUILD_ASSERT(DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_console), zephyr_cdc_acm_uart), 30 | // "Console device is not ACM CDC UART device"); 31 | 32 | void thread_com(struct k_lifo *data, enum conn_state *conn_state, struct k_mutex *mtx) { 33 | 34 | // TODO 35 | *conn_state = STATE_NOT_CONNECTED; 36 | 37 | // store date and time 38 | int64_t datetime_ms; 39 | time_t datetime_s; 40 | struct tm *datetime_tm; 41 | char datetime_str[DATE_TIME_LEN]; 42 | 43 | 44 | const struct device *const dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); 45 | uint32_t dtr = 0; 46 | 47 | /*if (usb_enable(NULL)) { 48 | return; 49 | }*/ 50 | 51 | /* Poll if the DTR flag was set */ 52 | /*while (!dtr) { 53 | uart_line_ctrl_get(dev, UART_LINE_CTRL_DTR, &dtr); 54 | // Give CPU resources to low priority threads. 55 | k_sleep(K_MSEC(100)); 56 | }*/ 57 | 58 | 59 | while(1) { 60 | 61 | printk("Hello World! %s\n", CONFIG_ARCH); 62 | k_sleep(K_SECONDS(1)); 63 | 64 | // if LIFO empty wait here 65 | //struct mdata_t *md = k_fifo_get(&mdata_fifo, K_FOREVER); 66 | 67 | 68 | // TODO: move this to the sens thread 69 | //date_time_now(&datetime_ms); 70 | //datetime_s = datetime_ms/1000; 71 | //datetime_tm = gmtime(&datetime_s); 72 | 73 | //strftime(datetime_str,DATE_TIME_LEN, "%Y-%m-%d %H:%M:%S.000000", datetime_tm); 74 | /*char payload[1024]= {"\0"}; 75 | sprintf(payload,"{\"time_measured\":\"%s\"," \ 76 | "\"data\": {" \ 77 | "\"ax\":\"%.3f\",\"ay\":\"%.3f\",\"az\":\"%.3f\"," \ 78 | "\"gx\":\"%.3f\",\"gy\":\"%.3f\",\"gz\":\"%.3f\"," \ 79 | "\"mx\":\"%.3f\",\"my\":\"%.3f\",\"mz\":\"%.3f\"," \ 80 | "\"temp\":\"%.3f\"}}", 81 | datetime_str, 82 | sensor_value_to_double(&md->ax), 83 | sensor_value_to_double(&md->ay), 84 | sensor_value_to_double(&md->az), 85 | sensor_value_to_double(&md->gx), 86 | sensor_value_to_double(&md->gy), 87 | sensor_value_to_double(&md->gz), 88 | sensor_value_to_double(&md->mx), 89 | sensor_value_to_double(&md->my), 90 | sensor_value_to_double(&md->mz), 91 | sensor_value_to_double(&md->temp) 92 | );*/ 93 | 94 | // TODO: TX 95 | 96 | } 97 | 98 | 99 | } 100 | -------------------------------------------------------------------------------- /samples/application/src/com.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #define MAX_RECV_BUF_LEN 2048 5 | 6 | #define DATE_TIME_LEN 27 7 | 8 | // Prototypes 9 | void thread_com(struct k_lifo *data, enum conn_state *conn_state, struct k_mutex *mtx); -------------------------------------------------------------------------------- /samples/application/src/common.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | enum conn_state { 5 | STATE_NOT_CONNECTED, 6 | STATE_LTE_CONNECTED, 7 | STATE_BACKEND_CONNECTED, 8 | STATE_ERROR 9 | }; 10 | 11 | // data structure 12 | struct mdata_t { 13 | void *reserved; /* 1st word reserved for use by fifo */ 14 | struct sensor_value ax; 15 | struct sensor_value ay; 16 | struct sensor_value az; 17 | struct sensor_value gx; 18 | struct sensor_value gy; 19 | struct sensor_value gz; 20 | struct sensor_value mx; 21 | struct sensor_value my; 22 | struct sensor_value mz; 23 | struct sensor_value temp; 24 | }; -------------------------------------------------------------------------------- /samples/application/src/led.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | LOG_MODULE_DECLARE(main_firmware, LOG_LEVEL_DBG); 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "common.h" 11 | #include "led.h" 12 | 13 | 14 | static const struct gpio_dt_spec led1_r = GPIO_DT_SPEC_GET(LED1_R_NODE, gpios); 15 | static const struct gpio_dt_spec led1_g = GPIO_DT_SPEC_GET(LED1_G_NODE, gpios); 16 | static const struct gpio_dt_spec led1_b = GPIO_DT_SPEC_GET(LED1_B_NODE, gpios); 17 | 18 | void timer_expired() { 19 | //gpio_pin_set_dt(&led1_g, 0); 20 | gpio_pin_set_dt(&led1_g, 0); 21 | } 22 | 23 | K_TIMER_DEFINE(timer, timer_expired, NULL); 24 | 25 | int led_off() { 26 | int ret = 0; 27 | ret |= gpio_pin_set_dt(&led1_r, 0); 28 | ret |= gpio_pin_set_dt(&led1_g, 0); 29 | ret |= gpio_pin_set_dt(&led1_b, 0); 30 | return ret; 31 | } 32 | 33 | void thread_led(enum conn_state *conn_state, void *arg2, void *arg3) 34 | { 35 | ARG_UNUSED(arg2); 36 | ARG_UNUSED(arg3); 37 | 38 | printk("LED control starting...\n"); 39 | 40 | if( gpio_pin_configure_dt(&led1_r, GPIO_OUTPUT_ACTIVE) < 0 || 41 | gpio_pin_configure_dt(&led1_g, GPIO_OUTPUT_ACTIVE) < 0 || 42 | gpio_pin_configure_dt(&led1_b, GPIO_OUTPUT_ACTIVE) < 0 ) { 43 | return; 44 | } 45 | 46 | led_off(); 47 | 48 | LOG_DBG("Succesfully initialized LED"); 49 | 50 | int ret; 51 | uint8_t prev_state = STATE_NOT_CONNECTED; 52 | 53 | while(1) { 54 | 55 | switch(*conn_state) { 56 | case STATE_NOT_CONNECTED: 57 | prev_state = STATE_NOT_CONNECTED; 58 | 59 | ret = gpio_pin_toggle_dt(&led1_b); 60 | ret = gpio_pin_toggle_dt(&led1_r); 61 | ret = gpio_pin_toggle_dt(&led1_g); 62 | k_sleep(K_MSEC(500)); 63 | break; 64 | 65 | case STATE_LTE_CONNECTED: 66 | prev_state = STATE_LTE_CONNECTED; 67 | 68 | ret = gpio_pin_set_dt(&led1_b, 1); 69 | 70 | k_sleep(K_MSEC(500)); 71 | break; 72 | 73 | case STATE_BACKEND_CONNECTED: 74 | if( prev_state != STATE_BACKEND_CONNECTED) { 75 | 76 | ret = gpio_pin_set_dt(&led1_b, 0); 77 | 78 | // turn green ON (turned OFF by timer callback) 79 | k_timer_start(&timer, K_MSEC(5000), K_NO_WAIT); 80 | //ret = gpio_pin_set_dt(&led1_g, 1); 81 | ret |= gpio_pin_set_dt(&led1_g, 1); 82 | 83 | } 84 | 85 | prev_state = STATE_BACKEND_CONNECTED; 86 | break; 87 | 88 | case STATE_ERROR: 89 | prev_state = STATE_ERROR; 90 | 91 | //ret = gpio_pin_set_dt(&led1_b, 0); 92 | //ret |= gpio_pin_set_dt(&led2_b, 0); 93 | //ret |= gpio_pin_toggle_dt(&led1_r); 94 | ret = gpio_pin_set_dt(&led1_b, 0); 95 | ret |= gpio_pin_toggle_dt(&led1_r); 96 | 97 | k_sleep(K_MSEC(1000)); 98 | break; 99 | } 100 | 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /samples/application/src/led.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | // devicetree 5 | #define LED1_R_NODE DT_ALIAS(led0) 6 | #define LED1_G_NODE DT_ALIAS(led1) 7 | #define LED1_B_NODE DT_ALIAS(led2) 8 | 9 | #define PERIOD_USEC (USEC_PER_SEC / 50U) 10 | #define PERIOD_NSEC (NSEC_PER_USEC * PERIOD_USEC) 11 | 12 | #define STEPSIZE_USEC 2000 13 | 14 | enum { RED, GREEN, BLUE }; 15 | 16 | // Prototypes 17 | void thread_led(enum conn_state *conn_state, void *arg2, void *arg3); 18 | -------------------------------------------------------------------------------- /samples/application/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Anything Connected 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | LOG_MODULE_REGISTER(main_firmware, LOG_LEVEL_DBG); 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | // local headers 16 | #include "common.h" 17 | #include "led.h" 18 | #include "com.h" 19 | //#include "sens.h" 20 | 21 | enum conn_state connected_global = STATE_NOT_CONNECTED; 22 | 23 | #define STACKSIZE 1024 24 | #define STACKSIZE_HI 4096 25 | 26 | #define SAMPLE_T 100 27 | 28 | #define SLEEP_TIME_MS 1000 29 | 30 | // threads 31 | K_THREAD_STACK_DEFINE(led_thread_stack_area, STACKSIZE); 32 | K_THREAD_STACK_DEFINE(sens_thread_stack_area, STACKSIZE); 33 | K_THREAD_STACK_DEFINE(com_thread_stack_area, STACKSIZE_HI); 34 | 35 | static struct k_thread led_thread_data; 36 | static struct k_thread sens_thread_data; 37 | static struct k_thread com_thread_data; 38 | 39 | #define THREAD_PRIORITY_HI 5 40 | #define THREAD_PRIORITY 7 41 | #define THREAD_PRIORITY_LOW 9 42 | 43 | K_MUTEX_DEFINE(mtx); 44 | struct k_fifo mdata_fifo; 45 | 46 | void main(void) 47 | { 48 | 49 | k_fifo_init(&mdata_fifo); 50 | 51 | // LEDs 52 | k_thread_create(&led_thread_data, led_thread_stack_area, K_THREAD_STACK_SIZEOF(led_thread_stack_area), 53 | (k_thread_entry_t) thread_led, 54 | &connected_global, NULL, NULL, 55 | THREAD_PRIORITY_LOW, 0, K_FOREVER); 56 | k_thread_name_set(&led_thread_data, "LED thread"); 57 | k_thread_start(&led_thread_data); 58 | 59 | // sensors 60 | /*k_thread_create(&sens_thread_data, sens_thread_stack_area, K_THREAD_STACK_SIZEOF(sens_thread_stack_area), 61 | (k_thread_entry_t) thread_sens, 62 | NULL, &connected_global, &mtx, 63 | THREAD_PRIORITY, 0, K_FOREVER); 64 | k_thread_name_set(&sens_thread_data, "SEN thread"); 65 | k_thread_start(&sens_thread_data);*/ 66 | 67 | // com 68 | k_thread_create(&com_thread_data, com_thread_stack_area, K_THREAD_STACK_SIZEOF(com_thread_stack_area), 69 | (k_thread_entry_t) thread_com, 70 | NULL, &connected_global, &mtx, 71 | THREAD_PRIORITY_HI, 0, K_FOREVER); 72 | k_thread_name_set(&com_thread_data, "COM thread"); 73 | k_thread_start(&com_thread_data); 74 | 75 | } 76 | -------------------------------------------------------------------------------- /samples/application/src/sens.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | LOG_MODULE_DECLARE(main_firmware, LOG_LEVEL_DBG); 4 | 5 | #include 6 | 7 | #include "ad5423.h" 8 | 9 | #include "common.h" 10 | #include "sens.h" 11 | 12 | extern struct k_fifo mdata_fifo; 13 | 14 | const struct device *dac; 15 | 16 | void thread_sens(struct k_lifo *data, enum conn_state *conn_state, struct k_mutex *mtx) 17 | { 18 | 19 | dac = DEVICE_DT_GET_ANY(adi_ad5423); 20 | 21 | // 22 | //const struct device *ad5423 = device_get_binding("AD5423"); 23 | 24 | if (!dac) { 25 | LOG_ERR("Failed to get device binding for AD5423"); 26 | return; 27 | } 28 | 29 | struct sensor_value accel[3], gyro[3], mag[4]; 30 | 31 | while(1) { 32 | 33 | get_chip_id(dac); 34 | //printk("SENS \n"); 35 | 36 | /*if(*conn_state == STATE_BACKEND_CONNECTED) { 37 | 38 | // get 6DOF 39 | //sensor_sample_fetch(iim42652); 40 | //sensor_channel_get(iim42652, SENSOR_CHAN_ACCEL_XYZ, accel); 41 | //sensor_channel_get(iim42652, SENSOR_CHAN_GYRO_XYZ, gyro); 42 | 43 | // get MAG 44 | //sensor_sample_fetch(mlx90393); 45 | //sensor_channel_get(mlx90393, SENSOR_CHAN_ALL, mag); 46 | 47 | struct mdata_t md = { 48 | .ax = accel[0], 49 | .ay = accel[1], 50 | .az = accel[2], 51 | .gx = gyro[0], 52 | .gy = gyro[1], 53 | .gz = gyro[2], 54 | .mx = mag[0], 55 | .my = mag[1], 56 | .mz = mag[2], 57 | .temp = mag[3] 58 | }; 59 | 60 | k_fifo_put(&mdata_fifo, &md); 61 | 62 | }*/ 63 | 64 | // slow down 65 | k_msleep( 1000 ); 66 | 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /samples/application/src/sens.h: -------------------------------------------------------------------------------- 1 | 2 | //#define THREAD_RATE_S 1 3 | #define THREAD_RATE_10S 10U 4 | #define THREAD_RATE_30S 30U 5 | #define THREAD_RATE_1MIN 60U 6 | #define THREAD_RATE_2MIN 120U 7 | #define THREAD_RATE_5MIN 300U 8 | #define THREAD_RATE_10MIN 600U 9 | 10 | #define THREAD_RATE_MS THREAD_RATE_10S 11 | 12 | // Prototypes 13 | void thread_sens(struct k_lifo *data, enum conn_state *conn_state, 14 | struct k_mutex *mtx); -------------------------------------------------------------------------------- /samples/application/src/shell.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Wrecklab BV 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | //#include "tmc5160.h" 11 | 12 | extern bool toggle; 13 | extern const struct device *tmc; 14 | 15 | static int cmd_lib_info(const struct shell *shell, size_t argc, char *argv[]) 16 | { 17 | //slave = (uint8_t) strtol(argv[CMD_ARG_N], &argv[CMD_ARG_N], 10); 18 | shell_fprintf(shell, SHELL_NORMAL, "Biond L.I.B. init info message %s\n", CONFIG_ARCH); 19 | //tmc_init(tmc, slave); 20 | 21 | return 0; 22 | } 23 | 24 | /*static int cmd_tmc(const struct shell *shell, size_t argc, char *argv[]) 25 | { 26 | slave = (uint8_t) strtol(argv[1], &argv[1], 10); 27 | return 0; 28 | } 29 | static int cmd_tmc_get(const struct shell *shell, size_t argc, char *argv[]) 30 | { 31 | uint32_t data; 32 | 33 | slave = (uint8_t) strtol(argv[CMD_ARG_N], &argv[CMD_ARG_N], 10); 34 | attr f = get_field(argv[CMD_ARG_N+1]); 35 | 36 | tmc_reg_read(tmc, slave, f.reg, &data); 37 | 38 | shell_fprintf(shell, SHELL_NORMAL, "GET - Field '%s' (reg 0x%02X) has value: %u \n", argv[CMD_ARG_N+1], f.reg, (data&f.mask)>>f.shift); 39 | 40 | //shell_fprintf(shell, SHELL_NORMAL, "GET - Field '%s' (reg 0x%02X) has value: %u \n", argv[CMD_ARG_N+1], f.reg, (data&f.mask)>>f.shift); 41 | 42 | return 0; 43 | } 44 | static int cmd_tmc_set(const struct shell *shell, size_t argc, char *argv[]) 45 | { 46 | uint32_t data; 47 | 48 | slave = (uint8_t) strtol(argv[CMD_ARG_N], &argv[CMD_ARG_N], 10); 49 | attr f = get_field(argv[CMD_ARG_N+1]); 50 | 51 | int32_t val = strtol(argv[CMD_ARG_N+2], &argv[CMD_ARG_N+2], 10); 52 | 53 | //tmc_reg_read(tmc, slave, f.reg, &data); 54 | //data &= ~f.mask; 55 | //data |= val<: %d\n", 0); 97 | return 0; 98 | } 99 | static int cmd_tmc_turn(const struct shell *shell, size_t argc, char *argv[]) 100 | { 101 | 102 | slave = (uint8_t) strtol(argv[CMD_ARG_N], &argv[CMD_ARG_N], 10); 103 | 104 | // increment/decrement current position by n (float) turns 105 | int32_t acc, speed; 106 | 107 | if(argc == CMD_ARG_N+3) { 108 | acc = (int32_t) strtol( argv[CMD_ARG_N+3], &argv[CMD_ARG_N+3], 10); 109 | tmc_set_amax(tmc, slave, acc); 110 | speed = (int32_t) strtol( argv[CMD_ARG_N+2], &argv[CMD_ARG_N+2], 10); 111 | tmc_set_vmax(tmc, slave, speed); 112 | } else if(argc == CMD_ARG_N+2) { 113 | speed = (int32_t) strtol( argv[CMD_ARG_N+2], &argv[CMD_ARG_N+2], 10); 114 | tmc_set_vmax(tmc, slave, speed); 115 | } 116 | 117 | //float turns = strtod(argv[1], &argv[1]); 118 | int32_t turns = (int32_t) strtol( argv[CMD_ARG_N+1], &argv[CMD_ARG_N+1], 10); 119 | 120 | int32_t steps = tmc_get_xtarget(tmc, slave); 121 | steps += (int32_t) (turns * DEFAULT_STEPS_TURN); 122 | 123 | tmc_set_xtarget(tmc, slave, 51200); 124 | 125 | return 0; 126 | } 127 | 128 | static int cmd_tmc_goto(const struct shell *shell, size_t argc, char *argv[]) 129 | { 130 | // rotate to absolute position [turns] 131 | 132 | //float turns = strtod(argv[1], &argv[1]); 133 | int32_t turns = (int32_t) strtol( argv[1], &argv[1], 10); 134 | 135 | int32_t steps = (int32_t) (turns * DEFAULT_STEPS_TURN); 136 | // TODO: 137 | //tmc_set_xtarget(tmc, slave, steps); 138 | 139 | return 0; 140 | } 141 | static int cmd_tmc_cur(const struct shell *shell, size_t argc, char *argv[]) 142 | { 143 | 144 | uint8_t irun = (uint8_t) strtol( argv[CMD_ARG_N+1], &argv[CMD_ARG_N+1], 10); 145 | uint8_t ihold = (uint8_t) strtol( argv[CMD_ARG_N+2], &argv[CMD_ARG_N+2], 10); 146 | 147 | slave = (uint8_t) strtol(argv[CMD_ARG_N], &argv[CMD_ARG_N], 10); 148 | 149 | tmc_set_irun_ihold(tmc, slave, irun, ihold); 150 | 151 | shell_fprintf(shell, SHELL_NORMAL, "Set TMC current I_RUN: %u, I_HOLD: %u \n", irun, ihold); 152 | 153 | return 0; 154 | } 155 | */ 156 | 157 | SHELL_STATIC_SUBCMD_SET_CREATE( lib_cmds, 158 | 159 | SHELL_CMD_ARG(info, NULL, "Get version and other info", 160 | cmd_lib_info, 1, 0), 161 | 162 | /*SHELL_CMD_ARG(dump, NULL, "Printout slave readable registers", 163 | cmd_tmc_dump, 2, 0), 164 | // run (start/stop) 165 | SHELL_CMD_ARG(run, NULL, "Start/Stop TMC stepper (at , optional accel)", 166 | cmd_tmc_run, 3, 1), 167 | // set mode (ramp or velocity) 168 | SHELL_CMD_ARG(mode, NULL, "Set TMC mode of operation. ($ tmc mode <0/1> // 0:velocity 1:ramp)", 169 | cmd_tmc_mode, 2, 0), 170 | // set/get register's field 171 | SHELL_CMD_ARG(get, NULL, "Get TMC register's field (tmc get )", 172 | cmd_tmc_get, 3, 0), 173 | SHELL_CMD_ARG(set, NULL, "Set TMC register's field (tmc set )", 174 | cmd_tmc_set, 4, 0), 175 | SHELL_CMD_ARG(turn, NULL, "Turn motor by n turns (1.5: increment, -1.5: decrement)", 176 | cmd_tmc_turn, 3, 2), 177 | SHELL_CMD_ARG(goto, NULL, "Move TMC to position", 178 | cmd_tmc_goto, 2, 0), 179 | SHELL_CMD_ARG(cur, NULL, "Set TMC run and hold current (0:min, 31:max)", 180 | cmd_tmc_cur, 4, 0),*/ 181 | 182 | SHELL_SUBCMD_SET_END 183 | ); 184 | 185 | // [0] [1] [2] 186 | // tmc 187 | SHELL_CMD_ARG_REGISTER(lib, &lib_cmds, "Biond Let It Beat control commands", NULL, 1, 0); -------------------------------------------------------------------------------- /samples/printhat1/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | # Add the driver directory as a zephyr module by hand 6 | list(APPEND ZEPHYR_EXTRA_MODULES 7 | ${CMAKE_CURRENT_SOURCE_DIR}/../../drivers 8 | ) 9 | 10 | # Re-direct the directory where the 'boards' directory is found from 11 | # $ZEPHYR_BASE to this directory. 12 | # set(BOARD_ROOT ${CMAKE_CURRENT_LIST_DIR}) 13 | set( 14 | BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../.. 15 | ) 16 | 17 | cmake_minimum_required(VERSION 3.20.0) 18 | 19 | # required for apps 20 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 21 | 22 | project(printhat1) 23 | 24 | zephyr_include_directories(src) 25 | 26 | target_sources(app PRIVATE 27 | src/main.c 28 | ) 29 | -------------------------------------------------------------------------------- /samples/printhat1/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_SHELL=y 2 | CONFIG_SHELL_LOG_BACKEND=y 3 | 4 | CONFIG_STDOUT_CONSOLE=y 5 | CONFIG_PRINTK=y 6 | 7 | CONFIG_LOG=y 8 | CONFIG_LOG_PRINTK=y 9 | CONFIG_LOG_MODE_IMMEDIATE=y 10 | CONFIG_LOG_BACKEND_UART=y 11 | 12 | CONFIG_PWM=y 13 | CONFIG_PWM_LOG_LEVEL_DBG=y 14 | 15 | CONFIG_SENSOR=y 16 | CONFIG_SENSOR_LOG_LEVEL_DBG=y 17 | 18 | # com stack 19 | #CONFIG_USB_DEVICE_STACK=y 20 | #CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=y 21 | #CONFIG_USB_DEVICE_PRODUCT="Zephyr Console" 22 | 23 | # selects TMC_SPI by default 24 | CONFIG_TMC2130=y 25 | -------------------------------------------------------------------------------- /samples/printhat1/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "tmc2130.h" 11 | 12 | #define SLEEP_TIME_MS 1000 13 | 14 | #define S1 DT_NODELABEL(s1) 15 | #define S2 DT_NODELABEL(s2) 16 | #define S3 DT_NODELABEL(s3) 17 | #define S4 DT_NODELABEL(s4) 18 | 19 | #define H0_NODE DT_ALIAS(h0) 20 | #define H1_NODE DT_ALIAS(h1) 21 | #define F0_NODE DT_ALIAS(f0) 22 | #define F1_NODE DT_ALIAS(f1) 23 | 24 | bool toggle; 25 | 26 | const struct device *tmc1 = DEVICE_DT_GET(S1); 27 | const struct device *tmc2 = DEVICE_DT_GET(S2); 28 | const struct device *tmc3 = DEVICE_DT_GET(S3); 29 | const struct device *tmc4 = DEVICE_DT_GET(S4); 30 | 31 | struct gpio_dt_spec h0 = GPIO_DT_SPEC_GET(H0_NODE, gpios); 32 | struct gpio_dt_spec h1 = GPIO_DT_SPEC_GET(H1_NODE, gpios); 33 | struct gpio_dt_spec f0 = GPIO_DT_SPEC_GET(F0_NODE, gpios); 34 | struct gpio_dt_spec f1 = GPIO_DT_SPEC_GET(F1_NODE, gpios); 35 | 36 | void main(void) 37 | { 38 | if( !device_is_ready(tmc1) || 39 | !device_is_ready(tmc2) || 40 | !device_is_ready(tmc3) || 41 | !device_is_ready(tmc4) ) { 42 | return; 43 | } 44 | 45 | if( !device_is_ready(h0.port) ) { 46 | return; 47 | } 48 | 49 | gpio_pin_configure_dt(&h0, GPIO_OUTPUT_ACTIVE); 50 | gpio_pin_configure_dt(&h1, GPIO_OUTPUT_ACTIVE); 51 | gpio_pin_configure_dt(&f0, GPIO_OUTPUT_ACTIVE); 52 | gpio_pin_configure_dt(&f1, GPIO_OUTPUT_ACTIVE); 53 | 54 | toggle = 0; 55 | 56 | uint32_t count = 0, data; 57 | uint8_t reg = TMC2130_GSTAT; 58 | 59 | while (1) { 60 | 61 | printk(" Heeeellooo %d\n", toggle); 62 | 63 | if(toggle) { 64 | gpio_pin_toggle_dt(&h0); 65 | gpio_pin_toggle_dt(&h1); 66 | gpio_pin_toggle_dt(&f0); 67 | gpio_pin_toggle_dt(&f1); 68 | } 69 | toggle = !toggle; 70 | 71 | 72 | tmc_reg_write(tmc1, 0, reg, 1); 73 | tmc_reg_read(tmc1, 0, reg, &data); 74 | printk( "Count %u - Register value: 0x%08X \n", count, data); 75 | 76 | count++; 77 | 78 | k_msleep(SLEEP_TIME_MS); 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /samples/printhat2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | # Add the driver directory as a zephyr module by hand 6 | list(APPEND ZEPHYR_EXTRA_MODULES 7 | ${CMAKE_CURRENT_SOURCE_DIR}/../../drivers 8 | ) 9 | 10 | # Re-direct the directory where the 'boards' directory is found from 11 | # $ZEPHYR_BASE to this directory. 12 | # set(BOARD_ROOT ${CMAKE_CURRENT_LIST_DIR}) 13 | set( 14 | BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../.. 15 | ) 16 | 17 | cmake_minimum_required(VERSION 3.20.0) 18 | 19 | # required for apps 20 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 21 | 22 | project(printhat2) 23 | 24 | zephyr_include_directories(src) 25 | 26 | target_sources(app PRIVATE 27 | src/main.c 28 | ) 29 | -------------------------------------------------------------------------------- /samples/printhat2/prj.conf: -------------------------------------------------------------------------------- 1 | #CONFIG_SHELL=y 2 | #CONFIG_SHELL_LOG_BACKEND=y 3 | 4 | #CONFIG_STDOUT_CONSOLE=y 5 | CONFIG_PRINTK=y 6 | 7 | CONFIG_LOG=y 8 | CONFIG_LOG_PRINTK=y 9 | CONFIG_LOG_MODE_IMMEDIATE=y 10 | #CONFIG_LOG_BACKEND_UART=y 11 | 12 | CONFIG_PWM=y 13 | CONFIG_PWM_LOG_LEVEL_DBG=y 14 | 15 | CONFIG_SENSOR=y 16 | CONFIG_SENSOR_LOG_LEVEL_DBG=y 17 | 18 | # com stack 19 | #CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=y 20 | CONFIG_USB_DEVICE_STACK=y 21 | CONFIG_USB_DEVICE_PRODUCT="Zephyr USB console sample" 22 | 23 | CONFIG_SERIAL=y 24 | CONFIG_CONSOLE=y 25 | CONFIG_UART_CONSOLE=y 26 | #CONFIG_UART_LINE_CTRL=y 27 | 28 | # steppers 29 | CONFIG_TMC_SD=y 30 | CONFIG_TMC2209=y 31 | -------------------------------------------------------------------------------- /samples/printhat2/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include "tmc2209.h" 13 | 14 | #define SLEEP_TIME_MS 5000 15 | 16 | #define S1 DT_NODELABEL(s1) 17 | #define S2 DT_NODELABEL(s2) 18 | #define S3 DT_NODELABEL(s3) 19 | 20 | #define H0_NODE DT_ALIAS(h0) 21 | #define H1_NODE DT_ALIAS(h1) 22 | #define H2_NODE DT_ALIAS(h2) 23 | #define F0_NODE DT_ALIAS(f0) 24 | #define F1_NODE DT_ALIAS(f1) 25 | 26 | bool toggle; 27 | 28 | const struct device *tmc1 = DEVICE_DT_GET(S1); 29 | const struct device *tmc2 = DEVICE_DT_GET(S2); 30 | const struct device *tmc3 = DEVICE_DT_GET(S3); 31 | 32 | struct gpio_dt_spec h0 = GPIO_DT_SPEC_GET(H0_NODE, gpios); 33 | struct gpio_dt_spec h1 = GPIO_DT_SPEC_GET(H1_NODE, gpios); 34 | struct gpio_dt_spec h2 = GPIO_DT_SPEC_GET(H2_NODE, gpios); 35 | struct gpio_dt_spec f0 = GPIO_DT_SPEC_GET(F0_NODE, gpios); 36 | struct gpio_dt_spec f1 = GPIO_DT_SPEC_GET(F1_NODE, gpios); 37 | 38 | struct gpio_dt_spec gpio4 = GPIO_DT_SPEC_GET( DT_NODELABEL(gp4), gpios ); 39 | 40 | void main(void) 41 | { 42 | const struct device *dev; 43 | int ret; 44 | 45 | dev = DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart); 46 | if (!device_is_ready(dev)) { 47 | printk("CDC ACM device not ready"); 48 | return; 49 | } 50 | 51 | ret = usb_enable(NULL); 52 | if (ret != 0) { 53 | printk("Failed to enable USB"); 54 | return; 55 | } 56 | 57 | 58 | if( !device_is_ready(tmc1) || 59 | !device_is_ready(tmc2) || 60 | !device_is_ready(tmc3) 61 | ) { 62 | return; 63 | } 64 | 65 | if( !device_is_ready(h0.port) ) { 66 | return; 67 | } 68 | 69 | gpio_pin_configure_dt(&h0, GPIO_OUTPUT_ACTIVE); 70 | gpio_pin_configure_dt(&h1, GPIO_OUTPUT_ACTIVE); 71 | gpio_pin_configure_dt(&h2, GPIO_OUTPUT_ACTIVE); 72 | gpio_pin_configure_dt(&f0, GPIO_OUTPUT_ACTIVE); 73 | gpio_pin_configure_dt(&f1, GPIO_OUTPUT_ACTIVE); 74 | 75 | gpio_pin_configure_dt(&gpio4, GPIO_OUTPUT_ACTIVE); 76 | 77 | toggle = 0; 78 | 79 | uint32_t count = 0, data; 80 | uint8_t reg = TMC2209_GSTAT; 81 | 82 | while (1) { 83 | 84 | gpio_pin_set_dt(&gpio4, 1); 85 | 86 | if(toggle) { 87 | gpio_pin_toggle_dt(&h0); 88 | gpio_pin_toggle_dt(&h1); 89 | gpio_pin_toggle_dt(&h2); 90 | gpio_pin_toggle_dt(&f0); 91 | gpio_pin_toggle_dt(&f1); 92 | } 93 | toggle = !toggle; 94 | 95 | tmc_reg_write(tmc1, 0, TMC2209_VACTUAL, 1); 96 | tmc_reg_read(tmc1, 0, TMC2209_IFCNT, &data); 97 | printk( "Count %u - Register value: 0x%08X \n", count, data); 98 | //tmc_dump(tmc1, 0); 99 | 100 | count++; 101 | 102 | k_msleep(SLEEP_TIME_MS); 103 | 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /samples/single-wire-irq/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | 5 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 6 | 7 | project(single-wire-irq) 8 | 9 | target_sources(app PRIVATE 10 | src/main.c 11 | ) 12 | -------------------------------------------------------------------------------- /samples/single-wire-irq/boards/nucleo_f103rb.overlay: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | / { 8 | aliases { 9 | uart1 = &usart1; 10 | uart2 = &usart3; 11 | }; 12 | }; 13 | 14 | &usart1 { 15 | single-wire; 16 | pinctrl-0 = <&usart1_tx_pa9>; 17 | }; 18 | 19 | &usart2 { 20 | // !!! default ST-LINK / debug port (zephyr console), 21 | // do not use here 22 | }; 23 | 24 | &usart3 { 25 | single-wire; 26 | pinctrl-0 = <&usart3_tx_pb10>; 27 | status = "okay"; 28 | }; -------------------------------------------------------------------------------- /samples/single-wire-irq/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_SERIAL=y 2 | CONFIG_UART_INTERRUPT_DRIVEN=y -------------------------------------------------------------------------------- /samples/single-wire-irq/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define UART_NODE1 DT_ALIAS(uart1) 13 | #define UART_NODE2 DT_ALIAS(uart2) 14 | 15 | const struct device *const uart1 = DEVICE_DT_GET(UART_NODE1); 16 | const struct device *const uart2 = DEVICE_DT_GET(UART_NODE2); 17 | 18 | #define N_RSP 4 19 | 20 | static int xfer_bytes; 21 | static char rd_data[12] = {0}; 22 | bool rcv = 0; 23 | 24 | void uart2_cb(const struct device *dev, void *user_data) 25 | { 26 | uint8_t c; 27 | 28 | if (!uart_irq_update(uart2)) { 29 | return; 30 | } 31 | 32 | if(uart_irq_rx_ready(uart2)) { 33 | 34 | xfer_bytes += uart_fifo_read(uart2, &rd_data[xfer_bytes], N_RSP - xfer_bytes); 35 | 36 | if (xfer_bytes == N_RSP) { 37 | xfer_bytes = 0; 38 | uart_irq_rx_disable(uart2); 39 | rcv = 1; 40 | } 41 | 42 | } 43 | } 44 | 45 | void main(void) 46 | { 47 | unsigned char recv; 48 | 49 | if (!device_is_ready(uart1) || !device_is_ready(uart2)) { 50 | printk("uart devices not ready\n"); 51 | return; 52 | } 53 | 54 | /* configure interrupt and callback to receive data */ 55 | uart_irq_callback_user_data_set(uart2, uart2_cb, NULL); 56 | 57 | xfer_bytes = 0; 58 | 59 | // flush uart 60 | uint8_t c; 61 | while (uart_fifo_read(uart2, &c, 1) > 0) { 62 | continue; 63 | } 64 | 65 | int ret; 66 | 67 | while (true) { 68 | 69 | if(rcv) { 70 | printk("%02X %02X %02X %02X \n", rd_data[0],rd_data[1],rd_data[2],rd_data[3]); 71 | rcv = 0; 72 | } 73 | 74 | uart_irq_rx_enable(uart2); 75 | 76 | // TX 77 | 78 | ret = uart_err_check(uart1); 79 | if(ret) { 80 | printk("UART error %d", ret); 81 | } 82 | 83 | 84 | unsigned char tx_buf[4] = { 0x0A, 0x0B, 0x0C, 0x0D }; 85 | for (int i=0; i; 17 | }; 18 | 19 | &usart2 { 20 | // !!! default ST-LINK / debug port (zephyr console), 21 | // do not use here 22 | }; 23 | 24 | &usart3 { 25 | single-wire; 26 | pinctrl-0 = <&usart3_tx_pb10>; 27 | status = "okay"; 28 | }; -------------------------------------------------------------------------------- /samples/single-wire/prj.conf: -------------------------------------------------------------------------------- 1 | # Nothing needed here 2 | -------------------------------------------------------------------------------- /samples/single-wire/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define UART_NODE1 DT_ALIAS(uart1) 13 | #define UART_NODE2 DT_ALIAS(uart2) 14 | 15 | const struct device *const sl_uart1 = DEVICE_DT_GET(UART_NODE1); 16 | const struct device *const sl_uart2 = DEVICE_DT_GET(UART_NODE2); 17 | 18 | void main(void) 19 | { 20 | unsigned char recv; 21 | 22 | if (!device_is_ready(sl_uart1) || !device_is_ready(sl_uart2)) { 23 | printk("uart devices not ready\n"); 24 | return; 25 | } 26 | 27 | while (true) { 28 | 29 | uint8_t i; 30 | 31 | // TX 32 | //uart_poll_out(sl_uart1, 'c'); 33 | unsigned char tx_buf[4] = { 0x0A, 0x0B, 0x0C, 0x0D }; 34 | for(i=0; i 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | list(APPEND ZEPHYR_EXTRA_MODULES 6 | ${CMAKE_CURRENT_SOURCE_DIR}/../../drivers 7 | ) 8 | 9 | cmake_minimum_required(VERSION 3.20.0) 10 | 11 | # required for apps 12 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 13 | 14 | project(tmc-sd) 15 | 16 | zephyr_include_directories(src) 17 | 18 | target_sources(app PRIVATE 19 | src/main.c 20 | ) 21 | -------------------------------------------------------------------------------- /samples/tmc-spi-sd/boards/nucleo_f103rb.overlay: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | 9 | / { 10 | aliases { 11 | uart1 = &usart1; 12 | uart2 = &usart2; 13 | tmc0 = &tmc_0; 14 | }; 15 | 16 | }; 17 | 18 | // USART1 tx:PA9 (rx:PA10, not used in single-wire mode) 19 | 20 | &timers1 { 21 | status = "okay"; 22 | st,prescaler = <100>; 23 | stepper0: pwm { 24 | status = "okay"; 25 | pinctrl-0 = < &tim1_ch1_pwm_pa8 >; 26 | pinctrl-names = "default"; 27 | }; 28 | }; 29 | 30 | &spi2 { 31 | cs-gpios = <&gpiob 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; 32 | 33 | tmc_0: tmc5160@0 { 34 | compatible = "trinamic,tmc5160"; 35 | status = "okay"; 36 | reg = <0x00>; 37 | 38 | // 4MHz internal, 8MHz external clock 39 | // TODO: seems not to work for higher speed than 1MHz 40 | spi-max-frequency = <1000000>; 41 | 42 | // step/dir 43 | pwms = <&stepper0 1 10000 PWM_POLARITY_NORMAL>; 44 | dir-gpios = <&gpioc 7 GPIO_ACTIVE_HIGH>; 45 | }; 46 | }; 47 | -------------------------------------------------------------------------------- /samples/tmc-spi-sd/prj.conf: -------------------------------------------------------------------------------- 1 | 2 | CONFIG_SHELL=y 3 | #CONFIG_SHELL_BACKEND_SERIAL_RX_POLL_PERIOD=100 4 | 5 | #CONFIG_SHELL_BACKEND_SERIAL=y 6 | #CONFIG_SHELL_MINIMAL=y 7 | #CONFIG_SHELL_LOG_BACKEND=y 8 | 9 | #CONFIG_UART_CONSOLE=y 10 | 11 | CONFIG_STDOUT_CONSOLE=y 12 | CONFIG_PRINTK=y 13 | 14 | CONFIG_LOG=y 15 | CONFIG_LOG_PRINTK=y 16 | CONFIG_LOG_MODE_IMMEDIATE=y 17 | 18 | CONFIG_GPIO=y 19 | CONFIG_PWM=y 20 | 21 | CONFIG_SENSOR=y 22 | CONFIG_SENSOR_LOG_LEVEL_DBG=y 23 | 24 | CONFIG_TMC_SPI=y 25 | CONFIG_TMC_SD=y 26 | CONFIG_TMC5160=y 27 | -------------------------------------------------------------------------------- /samples/tmc-spi-sd/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "tmc5160.h" 13 | 14 | #define SLEEP_TIME_MS 1000 15 | 16 | uint8_t toggle, toggle_old; 17 | 18 | const struct device *tmc0 = DEVICE_DT_GET( DT_ALIAS(tmc0) ); 19 | struct gpio_dt_spec led = GPIO_DT_SPEC_GET( DT_ALIAS(led0), gpios); 20 | 21 | #define SW0_NODE DT_ALIAS(sw0) 22 | #if !DT_NODE_HAS_STATUS(SW0_NODE, okay) 23 | #error "Unsupported board: sw0 devicetree alias is not defined" 24 | #endif 25 | static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, {0}); 26 | static struct gpio_callback button_cb_data; 27 | 28 | // start/stop motor 29 | void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { 30 | toggle = !toggle; 31 | } 32 | 33 | void main(void) 34 | { 35 | int ret; 36 | 37 | // config button 38 | if (!device_is_ready(button.port)) { 39 | printk("Error: button device %s is not ready\n", 40 | button.port->name); 41 | return; 42 | } 43 | 44 | ret = gpio_pin_configure_dt(&button, GPIO_INPUT); 45 | if (ret != 0) { 46 | printk("Error %d: failed to configure %s pin %d\n", 47 | ret, button.port->name, button.pin); 48 | return; 49 | } 50 | 51 | ret = gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_TO_ACTIVE); 52 | if (ret != 0) { 53 | printk("Error %d: failed to configure interrupt on %s pin %d\n", 54 | ret, button.port->name, button.pin); 55 | return; 56 | } 57 | 58 | gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin)); 59 | gpio_add_callback(button.port, &button_cb_data); 60 | printk("Set up button at %s pin %d\n", button.port->name, button.pin); 61 | 62 | 63 | // check tmc 64 | if (!device_is_ready(tmc0)) { 65 | printk("TMC device not ready\n"); 66 | return; 67 | } 68 | 69 | // config LED 70 | if( !device_is_ready(led.port) ) { 71 | return; 72 | } 73 | if( gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE) < 0 ) { 74 | return; 75 | } 76 | gpio_pin_set_dt(&led, 0); 77 | 78 | // set stand-still in speed mode 79 | //tmc_run(tmc0, 0, 0, 0); 80 | int8_t count = 0; 81 | 82 | while (1) { 83 | 84 | if(toggle!=toggle_old) { 85 | // set LED 86 | if( gpio_pin_set_dt(&led, toggle) < 0 ) { 87 | return; 88 | } 89 | 90 | count++; 91 | // start/stop motor 92 | if(count == 2) 93 | count=-1; 94 | 95 | tmc_run(tmc0, 0, count*60, 0); 96 | 97 | toggle_old = toggle; 98 | } 99 | 100 | k_sleep(K_MSEC(100)); 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /samples/tmc-spi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | cmake_minimum_required(VERSION 3.20.0) 6 | 7 | # required for apps 8 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 9 | 10 | project(tmc_spi) 11 | 12 | zephyr_include_directories(src) 13 | 14 | target_sources(app PRIVATE 15 | src/main.c 16 | ) 17 | -------------------------------------------------------------------------------- /samples/tmc-spi/boards/nucleo_f103rb.overlay: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | / { 8 | chosen { 9 | zephyr,console = &usart2; 10 | zephyr,shell-uart = &usart2; 11 | }; 12 | aliases { 13 | tmc0 = &tmc_0; 14 | motor0 = &motor_0; 15 | }; 16 | }; 17 | 18 | &spi2 { 19 | cs-gpios = <&gpiob 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; 20 | 21 | tmc_0: tmc5160@0 { 22 | compatible = "adi,tmc5160"; 23 | status = "okay"; 24 | reg = <0>; 25 | 26 | #address-cells = <1>; 27 | #size-cells = <0>; 28 | 29 | spi-max-frequency = ; 30 | 31 | clock-frequency = ; /* Int/Ext Clock frequency */ 32 | 33 | motor_0: motor@0 { 34 | status = "okay"; 35 | reg = <0>; 36 | 37 | /* common stepper controller settings */ 38 | invert-direction; 39 | micro-step-res = <1>; 40 | 41 | /* ADI TMC ramp generator as well as current settings */ 42 | vstart = <10>; 43 | a1 = <20>; 44 | v1 = <0>; 45 | d1 = <40>; 46 | vmax = <100>; 47 | amax = <60>; 48 | dmax = <70>; 49 | tzerowait = <80>; 50 | vhigh = <90>; 51 | vcoolthrs = <100>; 52 | ihold = <1>; 53 | irun = <16>; 54 | iholddelay = <3>; 55 | }; 56 | }; 57 | }; 58 | -------------------------------------------------------------------------------- /samples/tmc-spi/prj.conf: -------------------------------------------------------------------------------- 1 | 2 | CONFIG_SHELL=y 3 | CONFIG_SHELL_LOG_BACKEND=y 4 | 5 | CONFIG_SHELL_BACKEND_SERIAL=y 6 | 7 | CONFIG_STDOUT_CONSOLE=y 8 | CONFIG_PRINTK=y 9 | 10 | CONFIG_LOG=y 11 | CONFIG_LOG_PRINTK=y 12 | CONFIG_LOG_MODE_IMMEDIATE=y 13 | CONFIG_LOG_BACKEND_UART=y 14 | 15 | CONFIG_PWM=y 16 | CONFIG_PWM_LOG_LEVEL_DBG=y 17 | 18 | CONFIG_SENSOR=y 19 | CONFIG_SENSOR_LOG_LEVEL_DBG=y 20 | 21 | CONFIG_STEPPER=y 22 | CONFIG_STEPPER_SHELL=y 23 | #CONFIG_STEPPER_LOG_LEVEL_DBG=y 24 | -------------------------------------------------------------------------------- /samples/tmc-spi/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define SLEEP_TIME_MS 100 14 | #define SPEED_STEP_S 200 15 | 16 | uint8_t toggle, toggle_old; 17 | 18 | const struct device *tmc0 = DEVICE_DT_GET( DT_ALIAS(tmc0) ); 19 | const struct device *mot0 = DEVICE_DT_GET( DT_ALIAS(motor0) ); 20 | struct gpio_dt_spec led = GPIO_DT_SPEC_GET( DT_ALIAS(led0), gpios); 21 | 22 | #define SW0_NODE DT_ALIAS(sw0) 23 | #if !DT_NODE_HAS_STATUS(SW0_NODE, okay) 24 | #error "Unsupported board: sw0 devicetree alias is not defined" 25 | #endif 26 | static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, {0}); 27 | static struct gpio_callback button_cb_data; 28 | 29 | // start/stop motor 30 | void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { 31 | toggle = !toggle; 32 | } 33 | 34 | int main(void) { 35 | 36 | int ret; 37 | 38 | // config button 39 | if (!device_is_ready(button.port)) { 40 | printk("Error: button device %s is not ready\n", 41 | button.port->name); 42 | return -ENODEV; 43 | } 44 | 45 | ret = gpio_pin_configure_dt(&button, GPIO_INPUT); 46 | if (ret != 0) { 47 | printk("Error %d: failed to configure %s pin %d\n", 48 | ret, button.port->name, button.pin); 49 | return -ENODEV; 50 | } 51 | 52 | ret = gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_TO_ACTIVE); 53 | if (ret != 0) { 54 | printk("Error %d: failed to configure interrupt on %s pin %d\n", 55 | ret, button.port->name, button.pin); 56 | return -ENODEV; 57 | } 58 | 59 | gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin)); 60 | gpio_add_callback(button.port, &button_cb_data); 61 | printk("Set up button at %s pin %d\n", button.port->name, button.pin); 62 | 63 | 64 | 65 | // check tmc 66 | if (!device_is_ready(mot0)) { 67 | printk("TMC device not ready\n"); 68 | return -ENODEV; 69 | } 70 | stepper_enable(mot0, true); 71 | stepper_move(mot0, 200); 72 | //stepper_enable_constant_velocity_mode(mot0, STEPPER_DIRECTION_POSITIVE, SPEED_STEP_S); 73 | 74 | 75 | // config LED 76 | if( !device_is_ready(led.port) ) { 77 | return -ENODEV; 78 | } 79 | if( gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE) < 0 ) { 80 | return -ENODEV; 81 | } 82 | gpio_pin_set_dt(&led, 0); 83 | 84 | 85 | int8_t count = 0; 86 | 87 | while (1) { 88 | 89 | // set LED 90 | if( gpio_pin_toggle_dt(&led) < 0 ) { 91 | return -EIO; 92 | } 93 | 94 | /*if(toggle!=toggle_old) { 95 | 96 | count++; 97 | 98 | // start/stop motor 99 | if(count == 2){ 100 | stepper_enable_constant_velocity_mode(mot0, STEPPER_DIRECTION_POSITIVE, SPEED_STEP_S); 101 | } else if(count == 1) { 102 | stepper_enable_constant_velocity_mode(mot0, STEPPER_DIRECTION_NEGATIVE, SPEED_STEP_S); 103 | } 104 | 105 | if(count == 2) 106 | count=-1; 107 | 108 | //tmc_run(tmc0, 0, count*60, 0); 109 | // test ustep=1 110 | stepper_move(mot0, 200); 111 | 112 | toggle_old = toggle; 113 | }*/ 114 | 115 | k_msleep(SLEEP_TIME_MS); 116 | } 117 | 118 | return 0; 119 | } 120 | -------------------------------------------------------------------------------- /samples/tmc-uart-dma/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | list(APPEND ZEPHYR_EXTRA_MODULES 6 | ${CMAKE_CURRENT_SOURCE_DIR}/../../drivers 7 | ) 8 | 9 | cmake_minimum_required(VERSION 3.20.0) 10 | 11 | # required for apps 12 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 13 | 14 | project(tmc-uart) 15 | 16 | zephyr_include_directories(src) 17 | 18 | target_sources(app PRIVATE 19 | src/main.c 20 | ) 21 | -------------------------------------------------------------------------------- /samples/tmc-uart-dma/boards/nucleo_f103rb.overlay: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | 9 | / { 10 | aliases { 11 | uart1 = &usart1; 12 | uart2 = &usart2; 13 | tmc0 = &tmc_0; 14 | }; 15 | }; 16 | 17 | // see https://github.com/zephyrproject-rtos/zephyr/blob/db3f8c16e9c95801961a433c07f481bfcb385466/tests/drivers/uart/uart_async_api/boards/nucleo_f103rb.overlay 18 | &dma1 { 19 | //status = "okay"; 20 | }; 21 | 22 | // USART1 tx:PA9 rx:PA10 23 | // USART2 tx:PA2 rx:PA3 24 | // USART3 tx:PB10 rx:PB11 25 | &usart1 { 26 | 27 | /*dmas = <&dma1 4 0x440>, 28 | <&dma1 5 0x480>; 29 | dma-names = "tx", "rx"; 30 | */ 31 | 32 | single-wire; 33 | pinctrl-0 = <&usart1_tx_pa9>; 34 | 35 | tmc_0:tmc5160 { 36 | compatible = "trinamic,tmc5160"; 37 | status = "okay"; 38 | }; 39 | }; 40 | 41 | 42 | &usart2 { 43 | // !!! default ST-LINK / debug port (hence also zephyr console), don't use 44 | // it for TMC 45 | }; 46 | -------------------------------------------------------------------------------- /samples/tmc-uart-dma/prj.conf: -------------------------------------------------------------------------------- 1 | 2 | CONFIG_SHELL=y 3 | CONFIG_SHELL_LOG_BACKEND=y 4 | 5 | CONFIG_STDOUT_CONSOLE=y 6 | CONFIG_PRINTK=y 7 | 8 | CONFIG_LOG=y 9 | CONFIG_LOG_PRINTK=y 10 | CONFIG_LOG_MODE_IMMEDIATE=y 11 | #CONFIG_LOG_BACKEND_UART=y 12 | 13 | CONFIG_GPIO=y 14 | 15 | CONFIG_SENSOR=y 16 | CONFIG_SENSOR_LOG_LEVEL_DBG=y 17 | 18 | CONFIG_TMC5160=y 19 | CONFIG_TMC_UART=y 20 | 21 | # enable for DMA (must also enable DMA in .dts) 22 | CONFIG_UART_ASYNC_API=n 23 | 24 | # enable for INT (must also disable DMA in .dts) 25 | #CONFIG_UART_INTERRUPT_DRIVEN=n 26 | -------------------------------------------------------------------------------- /samples/tmc-uart-dma/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "tmc5160.h" 13 | 14 | #define UART_NODE1 DT_ALIAS(uart1) 15 | #define UART_NODE2 DT_ALIAS(uart2) 16 | 17 | #define SLEEP_TIME_MS 1000 18 | 19 | bool toggle; 20 | 21 | const struct device *tmc0 = DEVICE_DT_GET( DT_ALIAS(tmc0) ); 22 | struct gpio_dt_spec led = GPIO_DT_SPEC_GET( DT_ALIAS(led0), gpios); 23 | 24 | const struct device *uart1 = DEVICE_DT_GET(UART_NODE1); 25 | const struct device *uart2 = DEVICE_DT_GET(UART_NODE2); 26 | //const struct device *uart3 = DEVICE_DT_GET(UART_NODE3); 27 | 28 | void main(void) 29 | { 30 | // config UARTs 31 | if (!device_is_ready(uart1) || !device_is_ready(uart2)) { 32 | printk("uart devices not ready\n"); 33 | return; 34 | } 35 | 36 | // check tmc 37 | if (!device_is_ready(tmc0)) { 38 | printk("TMC device not ready\n"); 39 | return; 40 | } 41 | 42 | // config LED 43 | if( !device_is_ready(led.port) ) { 44 | return; 45 | } 46 | if( gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE) < 0 ) { 47 | return; 48 | } 49 | toggle = 1; 50 | 51 | uint8_t reg = TMC5160_GSTAT; 52 | //reg = TMC5160_INP_OUT; 53 | reg = TMC5160_RAMPMODE; 54 | uint32_t count = 0, data; 55 | 56 | while (1) { 57 | 58 | if(toggle) { 59 | if( gpio_pin_toggle_dt(&led) < 0 ) { 60 | return; 61 | } 62 | } 63 | 64 | //tmc_reg_write(tmc0, 0, reg, 1); 65 | //tmc_reg_read(tmc0, 0, TMC5160_IFCNT, &data); 66 | //printk( "Count %u - Register value: 0x%08X \n", count, data); 67 | 68 | toggle = !toggle; 69 | count++; 70 | 71 | k_sleep(K_MSEC(SLEEP_TIME_MS)); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /samples/tmc-uart/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Stefano Cottafavi 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | list(APPEND ZEPHYR_EXTRA_MODULES 6 | ${CMAKE_CURRENT_SOURCE_DIR}/../../drivers 7 | ) 8 | 9 | cmake_minimum_required(VERSION 3.20.0) 10 | 11 | # required for apps 12 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 13 | 14 | project(tmc-uart) 15 | 16 | zephyr_include_directories(src) 17 | 18 | target_sources(app PRIVATE 19 | src/main.c 20 | ) 21 | -------------------------------------------------------------------------------- /samples/tmc-uart/boards/nucleo_f103rb.overlay: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | 9 | / { 10 | aliases { 11 | uart1 = &usart1; 12 | uart2 = &usart2; 13 | tmc0 = &tmc_0; 14 | }; 15 | }; 16 | 17 | // USART1 tx:PA9 (rx:PA10, not used in single-wire mode) 18 | 19 | &usart1 { 20 | 21 | single-wire; 22 | pinctrl-0 = <&usart1_tx_pa9>; 23 | 24 | tmc_0:tmc5160 { 25 | compatible = "trinamic,tmc5160"; 26 | status = "okay"; 27 | }; 28 | }; 29 | -------------------------------------------------------------------------------- /samples/tmc-uart/prj.conf: -------------------------------------------------------------------------------- 1 | 2 | #CONFIG_SHELL=y 3 | #CONFIG_SHELL_BACKEND_SERIAL_RX_POLL_PERIOD=100 4 | 5 | #CONFIG_SHELL_BACKEND_SERIAL=y 6 | #CONFIG_SHELL_MINIMAL=y 7 | #CONFIG_SHELL_LOG_BACKEND=y 8 | 9 | #CONFIG_UART_CONSOLE=y 10 | 11 | CONFIG_STDOUT_CONSOLE=y 12 | CONFIG_PRINTK=y 13 | 14 | CONFIG_LOG=y 15 | CONFIG_LOG_PRINTK=y 16 | CONFIG_LOG_MODE_IMMEDIATE=y 17 | 18 | CONFIG_GPIO=y 19 | 20 | CONFIG_SENSOR=y 21 | CONFIG_SENSOR_LOG_LEVEL_DBG=y 22 | 23 | CONFIG_TMC_UART=y 24 | CONFIG_TMC5160=y 25 | -------------------------------------------------------------------------------- /samples/tmc-uart/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Stefano Cottafavi 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "tmc5160.h" 13 | 14 | #define UART_NODE1 DT_ALIAS(uart1) 15 | #define UART_NODE2 DT_ALIAS(uart2) 16 | 17 | #define SLEEP_TIME_MS 1000 18 | 19 | uint8_t toggle, toggle_old; 20 | 21 | const struct device *tmc0 = DEVICE_DT_GET( DT_ALIAS(tmc0) ); 22 | struct gpio_dt_spec led = GPIO_DT_SPEC_GET( DT_ALIAS(led0), gpios); 23 | 24 | const struct device *uart1 = DEVICE_DT_GET(UART_NODE1); 25 | const struct device *uart2 = DEVICE_DT_GET(UART_NODE2); 26 | 27 | #define SW0_NODE DT_ALIAS(sw0) 28 | #if !DT_NODE_HAS_STATUS(SW0_NODE, okay) 29 | #error "Unsupported board: sw0 devicetree alias is not defined" 30 | #endif 31 | static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, {0}); 32 | static struct gpio_callback button_cb_data; 33 | 34 | // start/stop motor 35 | void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { 36 | toggle = !toggle; 37 | } 38 | 39 | void main(void) 40 | { 41 | int ret; 42 | 43 | // config button 44 | if (!device_is_ready(button.port)) { 45 | printk("Error: button device %s is not ready\n", 46 | button.port->name); 47 | return; 48 | } 49 | 50 | ret = gpio_pin_configure_dt(&button, GPIO_INPUT); 51 | if (ret != 0) { 52 | printk("Error %d: failed to configure %s pin %d\n", 53 | ret, button.port->name, button.pin); 54 | return; 55 | } 56 | 57 | ret = gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_TO_ACTIVE); 58 | if (ret != 0) { 59 | printk("Error %d: failed to configure interrupt on %s pin %d\n", 60 | ret, button.port->name, button.pin); 61 | return; 62 | } 63 | 64 | gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin)); 65 | gpio_add_callback(button.port, &button_cb_data); 66 | printk("Set up button at %s pin %d\n", button.port->name, button.pin); 67 | 68 | 69 | 70 | // config UARTs 71 | if (!device_is_ready(uart1) || 72 | !device_is_ready(uart2)) { 73 | printk("uart devices not ready\n"); 74 | return; 75 | } 76 | 77 | // check tmc 78 | if (!device_is_ready(tmc0)) { 79 | printk("TMC device not ready\n"); 80 | return; 81 | } 82 | 83 | // config LED 84 | if( !device_is_ready(led.port) ) { 85 | return; 86 | } 87 | if( gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE) < 0 ) { 88 | return; 89 | } 90 | gpio_pin_set_dt(&led, 0); 91 | 92 | // set stand-still in speed mode 93 | tmc_run(tmc0, 0, 0, 0); 94 | 95 | while (1) { 96 | 97 | if(toggle!=toggle_old) { 98 | // set LED 99 | if( gpio_pin_set_dt(&led, toggle) < 0 ) { 100 | return; 101 | } 102 | // start/stop motor 103 | tmc_run(tmc0, 0, toggle*60, 0); 104 | 105 | toggle_old = toggle; 106 | } 107 | 108 | k_sleep(K_MSEC(100)); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /west.yml: -------------------------------------------------------------------------------- 1 | manifest: 2 | 3 | self: 4 | path: zephyr-trinamic 5 | 6 | remotes: 7 | - name: zephyr 8 | url-base: https://github.com/zephyrproject-rtos 9 | - name: trinamic 10 | url-base: https://github.com/cooked 11 | 12 | projects: 13 | - name: zephyr 14 | remote: zephyr 15 | revision: main 16 | import: 17 | name-allowlist: 18 | - cmsis 19 | - hal_stm32 20 | 21 | - name: hal_tmc 22 | remote: trinamic 23 | repo-path: TMC-API 24 | path: modules/hal/tmc 25 | revision: zephyr 26 | -------------------------------------------------------------------------------- /zephyr-trinamic.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | 8 | "settings": { 9 | "cortex-debug.JLinkGDBServerPath.linux": "/opt/SEGGER/JLink/JLinkGDBServerCLExe", 10 | "cortex-debug.armToolchainPath": "/usr/bin", 11 | "cortex-debug.armToolchainPrefix": "arm-none-eabi", 12 | "cortex-debug.gdbPath": "gdb-multiarch", 13 | 14 | // You're going to use tabs, Mr. Anderson. Whether you want to or not. 15 | "editor.insertSpaces": false, 16 | "editor.tabSize": 4, 17 | "editor.rulers": [ 18 | 80, 19 | 100 20 | ], 21 | "search.showLineNumbers": true, 22 | "explorer.confirmDelete": false, 23 | "debug.onTaskErrors": "abort", 24 | "files.trimFinalNewlines": true, 25 | "files.trimTrailingWhitespace": true, 26 | "diffEditor.ignoreTrimWhitespace": false, 27 | "rewrap.autoWrap.enabled": true, 28 | 29 | // Increase scrollback for integrated terminal so that we can see all 30 | // the output of our scripts 31 | // https://github.com/Microsoft/vscode/issues/63452 32 | "terminal.integrated.scrollback": 99999, 33 | "C_Cpp.errorSquiggles": "Enabled", 34 | "C_Cpp.default.includePath": [ 35 | 36 | ], 37 | }, 38 | 39 | } -------------------------------------------------------------------------------- /zephyr/module.yml: -------------------------------------------------------------------------------- 1 | build: 2 | cmake: . 3 | kconfig: Kconfig 4 | settings: 5 | dts_root: . 6 | board_root: . --------------------------------------------------------------------------------