The Pico has a set of PIO co-processors. They are real-time controllers that can execute logic with deterministic timing. Ideal to run strict-timed sequences and state machines. And to implement extra peripherals. |
Follow up of Stepper Motor Control with Raspberry Pico PI and DRV8711 driver- Part 1: Hardware Provisioning
SPI requirements and setup
The TI DRV8711 stepper motor driver, that we use in this project, relies on pre-configuration via SPI.
These are the Pico resources I reserve:
signal | DRV8711 | Pico |
SPI CLK | SCLK | default SCLK |
SPI CS | SCS | default CS* |
SPI MISO | sdato | default MISO** |
SPI MOSI | sdati | default MOSI |
* DRV8711 uses a chip select that's active high. Pico's SPI library doesn't support that, so I will bit bang that pin.
** DRV8711 uses open collector for outputs. Pico will have to provide the rail via a pull-up.
The setup code isn't complex. You 'll recognise the special cases mentioned below:
void init_spi_hw() { // Enable SPI 0 at 1 MHz and connect to GPIOs spi_init(spi_default, 1000 * 1000); spi_set_format(spi_default, 16, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST); // 16 bit registers gpio_set_function(PICO_DEFAULT_SPI_RX_PIN, GPIO_FUNC_SPI); gpio_set_pulls(PICO_DEFAULT_SPI_RX_PIN, true, false); // drv8711 outputs are open drain gpio_set_function(PICO_DEFAULT_SPI_SCK_PIN, GPIO_FUNC_SPI); gpio_set_function(PICO_DEFAULT_SPI_TX_PIN, GPIO_FUNC_SPI); // Chip select is active-high, so we'll initialise it to a driven-low state gpio_init(PICO_DEFAULT_SPI_CSN_PIN); gpio_put(PICO_DEFAULT_SPI_CSN_PIN, 0); gpio_set_dir(PICO_DEFAULT_SPI_CSN_PIN, GPIO_OUT); }
I provided helpers for CS and 16 bit write (the width of the DRV8711 registers):
static inline void cs_drive(bool high) { asm volatile("nop \n nop \n nop"); // FIXME gpio_put(PICO_DEFAULT_SPI_CSN_PIN, high? 1 : 0); asm volatile("nop \n nop \n nop"); // FIXME } static void spi_write(const uint16_t &data) { cs_drive(true); // drv8711 has CS active high spi_write16_blocking(spi_default, &data, 1); cs_drive(false); }
Here's an example of writing to a register (the structure used in the example uses Texas Instruments' registers.h file that comes with their DRV8711 examples).:
uint16_t data; // CTRL Register G_CTRL_REG.Address = 0x0000; G_CTRL_REG.DTIME = 0x0003; G_CTRL_REG.ISGAIN = 0x0003; G_CTRL_REG.EXSTALL = 0x0000; // G_CTRL_REG.MODE = 0x0003; // in 8th steps G_CTRL_REG.MODE = 0x0000; // in full steps G_CTRL_REG.RSTEP = 0x0000; G_CTRL_REG.RDIR = 0x0000; G_CTRL_REG.ENBL = 0x0001; // Write CTRL Register data = REGWRITE | (G_CTRL_REG.Address << 12) | (G_CTRL_REG.DTIME << 10) | (G_CTRL_REG.ISGAIN << 8) |(G_CTRL_REG.EXSTALL << 7) | (G_CTRL_REG.MODE << 3) | (G_CTRL_REG.RSTEP << 2) | (G_CTRL_REG.RDIR << 1) | (G_CTRL_REG.ENBL); spi_write(data);
The full code will be attached when I'm a bit further into this project. Next post will focus on provisioning the non-SPI pins.
Meanwhile: here's the full conversation from Pico to DRV8711: