I decided to document the steps needed to get the Low Power SPI working on iMXRT1050-EVKB and I hope it could be useful for other people using this board. But the basic idea apply to any other board supported by NuttX.
Everything starts with the schematic, you need to spot the SPI pins that you want to use and which SPI Port it belongs to.
Right, so we found the SPI pins and its MCU pins:
D10/SPI_CS -> GPIO_SD_B0_01
D11/OC2A/PWM/SPI_MOSI -> GPIO_SD_B0_02
D12/SPI_MISO -> GPIO_SD_B0_03
D13/SPI_CLK -> GPIO_SD_B0_00
Now we can find these pins definition on NuttX looking at the file arch/arm/src/imxrt/hardware/rt105x/imxrt105x_pinmux.h :
#define GPIO_LPSPI1_PCS0_2 (GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_01_INDEX)) #define GPIO_LPSPI1_SDO_2 (GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_02_INDEX)) #define GPIO_LPSPI1_SDI_2 (GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_03_INDEX)) #define GPIO_LPSPI1_SCK_2 (GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_00_INDEX))
Perfect, but here you need to know an important information about NuttX: normally the NuttX SPI drivers don’t use the native CS (Chip Select) pin, instead it use ordinary GPIO pins to work as CS. The reason behind it is because normally the SPI Hardware has a limited number os HW CS pins (normally 4 pins). So instead of limiting the user to only 4 devices (CS), NuttX allow you to use how many CS pins as you wish.
Now we need to see in the LPSPI driver what is the name of pins it uses, so we will associate these pins to those from the pinmux header file.
Just open the file arch/arm/src/imxrt/imxrt_lpspi.c and search for imxrt_config_gpio(), this is the function used to configure the pins on iMXRT10xx chips.
imxrt_config_gpio(GPIO_LPSPI1_SCK); imxrt_config_gpio(GPIO_LPSPI1_MISO); imxrt_config_gpio(GPIO_LPSPI1_MOSI);
All we need to do is to point these pins to our SPI pins (that we found in the pinmux.h).
You can do it adding these line to boards/arm/imxrt/imxrt1050-evk/include/board.h file:
#define GPIO_LPSPI1_SCK (GPIO_LPSPI1_SCK_2|IOMUX_LPSPI_DEFAULT) #define GPIO_LPSPI1_MISO (GPIO_LPSPI1_SDI_2|IOMUX_LPSPI_DEFAULT) #define GPIO_LPSPI1_MOSI (GPIO_LPSPI1_SDO_2|IOMUX_LPSPI_DEFAULT)
Ok, but where is the the Chip Select pin?
Don’t worry, if you look at iMXRT1050 Datasheet you will see that this CS pin (GPIO_SD_B0_01) is the GPIO3.IO[13] and it is already defined at boards/arm/imxrt/imxrt1050-evk/src/imxrt1050-evk.h this way:
#define GPIO_LPSPI1_CS (GPIO_OUTPUT | GPIO_OUTPUT_ONE | \ GPIO_PORT3 | GPIO_PIN13 | IOMUX_LPSPI1_CS)
So, with the basic configuration in place, now we can start defining our SPI device initialization. Let me think what SPI device we could you. Well, since I want you to “see” the SPI working, let’s to use the MAX7219 7-segment numeric display! đ
Fortunately we have the boards/arm/stm32/stm32f4discovery/src/stm32_max7219_leds.c as example to initialize our MAX7219 display.
We can copy it and modify to become an iMXRT file:
$ cp boards/arm/stm32/stm32f4discovery/src/stm32_max7219_leds.c boards/arm/imxrt/imxrt1050-evk/src/imxrt_max7219_leds.c
Replace all references to stm32f4discovery with imxrt1050-evk and all stm32 with imxrt!
You need to take care with some functions name replacement, ie:
stm32_spibus_initialize(MAX7219_SPI_PORTNO);
will become:
imxrt_lpspibus_initialize(MAX7219_SPI_PORTNO);
We are almost done, but we need to define this file to be compiled and we need to call its initialization function to register the display device.
To compile this file we just need to edit the file boards/arm/imxrt/imxrt1050-evk/src/Makefile and add these lines:
ifeq ($(CONFIG_LEDS_MAX7219),y)
CSRCS += imxrt_max7219_leds.c
endif
And to call the initialization we just add these lines to boards/arm/imxrt/imxrt1050-evk/src/imxrt_bringup.c inside imxrt_bringup() function:
#ifdef CONFIG_LEDS_MAX7219
ret = imxtrt_max7219init("/dev/numdisp0");
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: max7219_leds_register failed: %d\n", ret);
}
#endif
After everything is in place you can configure your iMXRT1050-EVK board, enter in the menuconfig and select:
System Type -> i.MX RT Peripheral Selection -> LPSPI Peripherals -> [*] LPSPI1
Device Drivers -> [*] SPI Driver Support
Device Drivers -> LED Support -> [*] MAX7219 Numeric Display
Save and Exit. Just type “make” to compile.
When the compilation finish you can look at the System.map file and search for max7219, you should see these symbols:
6000f954 T imxrt_max7219init
6000f974 t max7219_open
6000f978 t max7219_read
6000f97e t max7219_write16.isra.0
6000f9f4 t max7219_write
6000fb4e t max7219_close
6000fb52 T max7219_leds_register
Flash the firmware in the board (with SW7 1-off 2-on 3-on 4-off I just dropped the nuttx.hex in the disk), open the /dev/ttyACM0 and reset the board, you show see:
NuttShell (NSH) NuttX-9.1.0 nsh> uname -a NuttX 9.1.0 9a1391d36b-dirty Aug 8 2020 12:23:10 arm imxrt1050-evk nsh> ls /dev /dev: console null numdisp0 ttyS0 nsh>
As you can see our /dev/numdisp0 is there!
Note: you need to solder the resistors R281, R279, R278 and R280 to get LPSPI1 working.