Peripherals from M4 while Linux is running

Hi,
I am running a bare metal code on M4 of my Verdin Mini, parallel to Linux. I use several interfaces from the M core, as you can see from my pinmux:

  //DEBUG UART4
    IOMUXC_SetPinMux(IOMUXC_UART4_RXD_UART4_RX, 0U);
    IOMUXC_SetPinConfig(IOMUXC_UART4_RXD_UART4_RX, 
                        IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
                        IOMUXC_SW_PAD_CTL_PAD_FSEL(2U));
    IOMUXC_SetPinMux(IOMUXC_UART4_TXD_UART4_TX, 0U);
    IOMUXC_SetPinConfig(IOMUXC_UART4_TXD_UART4_TX, 
                        IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
                        IOMUXC_SW_PAD_CTL_PAD_FSEL(2U));


    //ECSPI2
    IOMUXC_SetPinMux(IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK, 0U);
    IOMUXC_SetPinConfig(IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK, 
                        IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
                        IOMUXC_SW_PAD_CTL_PAD_FSEL(2U));
    IOMUXC_SetPinMux(IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI , 0U);
    IOMUXC_SetPinConfig(IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI , 
                        IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
                        IOMUXC_SW_PAD_CTL_PAD_FSEL(2U));
    IOMUXC_SetPinMux(IOMUXC_ECSPI2_MISO_ECSPI2_MISO, 0U);
    IOMUXC_SetPinConfig(IOMUXC_ECSPI2_MISO_ECSPI2_MISO, 
                        IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
                        IOMUXC_SW_PAD_CTL_PAD_FSEL(2U));

    IOMUXC_SetPinMux(IOMUXC_ECSPI2_SS0_GPIO5_IO13, 0U); // slave select pin as GPIO ! software controlled
    IOMUXC_SetPinConfig(IOMUXC_ECSPI2_SS0_GPIO5_IO13, 
                        IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
                        IOMUXC_SW_PAD_CTL_PAD_FSEL(2U));

    //FPGA Ready
    IOMUXC_SetPinMux(IOMUXC_SAI3_TXFS_GPIO4_IO31 , 0U);
    IOMUXC_SetPinConfig(IOMUXC_SAI3_TXFS_GPIO4_IO31 , 
                        IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
                        IOMUXC_SW_PAD_CTL_PAD_FSEL(2U));

    


    //ECSPI1
    IOMUXC_SetPinMux(IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK , 0U);
    IOMUXC_SetPinConfig(IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK , 
                        IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
                        IOMUXC_SW_PAD_CTL_PAD_FSEL(2U));
                        
    IOMUXC_SetPinMux(IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI , 0U);
    IOMUXC_SetPinConfig(IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI , 
                        IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
                        IOMUXC_SW_PAD_CTL_PAD_FSEL(2U));

    IOMUXC_SetPinMux(IOMUXC_ECSPI1_MISO_ECSPI1_MISO , 0U);
    IOMUXC_SetPinConfig(IOMUXC_ECSPI1_MISO_ECSPI1_MISO , 
                        IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
                        IOMUXC_SW_PAD_CTL_PAD_FSEL(2U));
    
    IOMUXC_SetPinMux(IOMUXC_ECSPI1_SS0_GPIO5_IO09 , 0U); // SPI1 CS MUX
    IOMUXC_SetPinConfig(IOMUXC_ECSPI1_SS0_GPIO5_IO09 , 
                        IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
                        IOMUXC_SW_PAD_CTL_PAD_FSEL(2U));
    
    IOMUXC_SetPinMux(IOMUXC_NAND_CE3_B_GPIO3_IO04, 0U);  // SPI1 CS DAC
    IOMUXC_SetPinConfig(IOMUXC_NAND_CE3_B_GPIO3_IO04, 
                        IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
                        IOMUXC_SW_PAD_CTL_PAD_FSEL(2U));
    
    IOMUXC_SetPinMux(IOMUXC_UART3_RXD_GPIO5_IO26 , 0U); // SPI1 CS BP
    IOMUXC_SetPinConfig(IOMUXC_UART3_RXD_GPIO5_IO26 , 
                        IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
                        IOMUXC_SW_PAD_CTL_PAD_FSEL(2U));
    
    //SPI1 Reset, always high
    IOMUXC_SetPinMux(IOMUXC_UART3_TXD_GPIO5_IO27, 0U);
    IOMUXC_SetPinConfig(IOMUXC_UART3_TXD_GPIO5_IO27, 
                        IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
                        IOMUXC_SW_PAD_CTL_PAD_FSEL(2U));

The problem is that when the linux is running, the Verdin suddenly restarts after some time (approx. a minute, not always the same).
I think I managed to locate the problem at the FPGA_Ready pin that I’m using (GPIO4_IO31).
This pin is used as an input and it triggeres an interrupt handler that sets a flag fpgaReady = true, so that the SPI can read the data from the fpga slave.
Some additional code snippets for context:


#define FPGA_READY_GPIO_PIN   31U // fpga ready to send signal
#define FPGA_READY_GPIO   GPIO4

void fpga_ready_enableInterrupt(){
    GPIO_PortEnableInterrupts(FPGA_READY_GPIO, 1U << FPGA_READY_GPIO_PIN); 
}
void GPIO4_Combined_16_31_IRQHandler(void)
{
    fpgaReady = true;
    GPIO_ClearPinsInterruptFlags(FPGA_READY_GPIO, 1U << FPGA_READY_GPIO_PIN);

}

bool is_FPGA_ready(void){
    return fpgaReady;
}

The program doesn’t break when I turn off the linux in U-boot, so my guess is that I have some device tree interference. I created a custom overlay by slightly changing the overlay that was turned on by default, that is: verdin-imx8mm_lt8912_overlay.dts

// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
/*
 * Copyright 2020-2021 Toradex
 */

// Verdin DSI to HDMI Adapter orderable at Toradex.

/dts-v1/;
/plugin/;

/ {
        compatible = "toradex,verdin-imx8mm";
};

&gpu {
        status = "okay";
};


&pwm1 {
        status = "disabled";
};


/* Disable Verdin SPI */
&uart2 {
        status = "disabled";
        };
&uart3 {
        status = "disabled";
        };
&ecspi1 {
        status = "disabled";
        };

&ecspi2 {
        status = "disabled";
        };

I disabled the SPIs and UARTs that I’m using on the M side. In the case of the fpgaReady pin, it is the SODIMM 129 and the part of the uart2 by default, so I tought turning the UART2 off should solve this issue. It doesn’t :slight_smile:

My additional question would also be: Do I have to disable all GPIO pins in the device tree that I’m using (e.g. three Chip Select pins for SPI1 that I use) on the M-Core and how do I do that?

Thanks in advance!

Update:
I found in this thread that I have to disable the whole bank inside the device tree that I’ll be using from the M-Core. When I tried disabling two GPIO banks (&gpio1 and &gpio4) my ethernet stopped working and I had to reboot Linux from recovery mode. Was it some mistake on my end? Am I allowed to simply disable all gpio banks in linux device tree overlay?

Hi @swiss,

I think I was able to understand everything, please let me know if I answered something wrong.

This is strange, disabling uart2 from the Linux side should be enough for Linux not to change this pin. Did you add the overlay to overlays.txt and then run the sync command?

When you say “should solve this issue but it doesn’t”, what exactly is happening with this pin?

This pin is being used under pinctrl_uart2 in imx8mm-verdin.dtsi:

	pinctrl_uart2: uart2grp {
		fsl,pins = <
			MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_TX		0x146	/* SODIMM 129 */
			MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_RX		0x146	/* SODIMM 131 */
			MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B		0x146	/* SODIMM 133 */
			MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B		0x146	/* SODIMM 135 */
		>;
	};

You can also try to delete this group and compile the whole device tree again to see if this takes effect or not. However, this would be the same as setting the uart2 as disabled, as you did, so probably it won’t take too much effect.
If you want to try this, please follow this guide: Build From Source Code Documentation Overview | Toradex Developer Center
You will have to execute the following command to compile the whole device tree:

$ make DTC_FLAGS="-@" freescale/<device-tree>.dtb

In general, you should always disable everything that you are using in the Cortex-M4 from Linux. While the kernel is booting, it could access peripherals that are described inside the device tree and break something that M4 is trying to do. You can do that by creating an overlay and by disabling everything that you’re using in the M4, just as you did. I’m not sure exactly why with the uart2 it didn’t work. I’ll have to try this on my side as well.

Disabling these two banks, you are disabling some pins that are used by the ethernet connector and also by the wake-up source, as you can see from the following codes (extracted from imx8mm-verdin.dtsi as well):

/* Verdin ETH_1 (on-module PHY) */
&fec1 {
	fsl,magic-packet;
	phy-handle = <&ethphy0>;
	phy-mode = "rgmii-id";
	phy-supply = <&reg_ethphy>;
	pinctrl-names = "default", "sleep";
	pinctrl-0 = <&pinctrl_fec1>;
	pinctrl-1 = <&pinctrl_fec1_sleep>;

	mdio {
		#address-cells = <1>;
		#size-cells = <0>;

		ethphy0: ethernet-phy@7 {
			compatible = "ethernet-phy-ieee802.3-c22";
			interrupt-parent = <&gpio1>;
			interrupts = <10 IRQ_TYPE_LEVEL_LOW>;
			micrel,led-mode = <0>;
			reg = <7>;
		};
	};
};
	gpio-keys {
		compatible = "gpio-keys";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_gpio_keys>;

		wakeup {
			debounce-interval = <10>;
			/* Verdin CTRL_WAKE1_MICO# (SODIMM 252) */
			gpios = <&gpio4 28 GPIO_ACTIVE_LOW>;
			label = "Wake-Up";
			linux,code = <KEY_WAKEUP>;
			wakeup-source;
		};
	};

That’s why your module stopped working. Disabling the whole bank is not a good idea, since some peripherals are using some pins inside these banks.

I have some questions from my side, are you using the non-wifi or the wifi version of verdin imx8mm? Is it mandatory to use the SODIMM 129 pin or can you use a different pin?

Best Regards,
Hiago.

Hi @hfranco.tx ,
Sorry for the late response.

Please find attached the video of the unwanted behaviaour.
2022-10-05 11-24-23.mkv (224.0 KB)
You can see the two serials connections, one with the M4 one the left and the U-Boot/Linux on the right. The C is pretty much just and endless loop with the pin interrupt enabled, which is also printed out in the terminal. The interrupt enable function and its handler look like this:

void fpga_ready_enableInterrupt(){
    PRINTF("enabled\r\n");
    GPIO_PortEnableInterrupts(FPGA_READY_GPIO, 1U << FPGA_READY_GPIO_PIN); 
}

void GPIO4_Combined_16_31_IRQHandler(void)
{
    PRINTF("i\t");
    fpgaReady = true;
    GPIO_ClearPinsInterruptFlags(FPGA_READY_GPIO, 1U << FPGA_READY_GPIO_PIN);

}

I then produce a 20Hz clock signal as an input for the GPIO pin. As you can see interrupt stops reacting at one point of linux booting process. It is also very intereseting that if I enable the interrupt AFTER the linux boots (by sending a command through terminal) the interrupt keeps working.

I am using wifi version, even though we do not need the wifi for now. We actually use our custom board as well, but so far after around 2 months of testing, the verdin behaved identically regardless of the carrier board. I am testing with the dahlia right now though.

No, that was actually a short term solution, I want to use another GPIO pin for this purpose (SODIMM 216,218,220,222 would be the best for me).

I just tried SODIMM 216 (GPIO1_IO0) and the results are even more confusing then with the 129, I am uploading a video again because I can’t describe them:
2022-10-05 11-56-26.mkv (364.9 KB)

That’s without disabling this pin in the device tree overlay though. Let’s concentrate on one pin, let’s say 216. Can you help me disable it in a device tree overlay?
Thanks in advance.

P.S.:

I am pretty new to device trees so I feel like compiling a new one instead of using an overlay would just add additional error sources to this problem.
I checked under the linux /dev and only verdin-uart3 is enabled, so that tells me that my overlay should be working correctly.

Hi !

I also have some unexpected reboots. Do you have any kernel crash log on UART when it reboots ?

Thanks
Adrian

HI @luciolis,

There is no info on the UART when the crash happens. I also tried with a Segger J-Link debugger to “catch” the crash but I wasn’t able to. Sadly I don’t have the time to reproduce it right now, but when debugging over Segger and the system restarts, it stops on a certian breakpoint which indicates that the system unexpectedly restarted. My limited knowledge tells me that this breakpoint is too late, since it happens after the system has already crashed so I couldn’t pull any log info about the crash.

Hi @swiss,

Sorry for the delay, I was doing some tests here on my side, and apparently we need to disable the whole bank. The problem with that is other pins that use the same pin for important stuff, such as storage control, uart…

Checking the Verdin iMX8MM Datasheet and searching for gpio3, I think that disabling bank number 3 will have the least impact compared to other banks.

So I created the following overlay:

/dts-v1/;
/plugin/;

// Disable gpio3 bank from Linux to use with M4 core

/ {
	compatible = "toradex,verdin-imx8mm";
};

&gpio3 {
    status = "disabled";
};

You can download it here, the compiled version: Download - Toradex File Sharing Platform

I added it to my overlays.txt file. It contains only this overlay, I deleted the others.

After reboot, I searched for pin 206 (which is GPIO3.IO4), and I didn’t find anything:

# gpioinfo | grep -E "(SODIMM_206|gpiochip)"
gpiochip0 - 32 lines:
gpiochip1 - 32 lines:
gpiochip2 - 32 lines:
gpiochip3 - 32 lines:

So I guess the overlay is working now. Could you please use this overlay and use pin 206 as an interrupt for your m4 core?

Let me know if this solved your issue.

Best Regards,
Hiago.

Hi @hfranco.tx ,
I added the gpio3 disable to my device tree overlay and this does seem to solve the problem. The test I showed in the videos above passes now. I guess I would have to test a bit more to be completely sure.

Though this is the only pin where I’m using an interrupt, I still have a few more GPIO pins that I have to use, as you can see from my pinmux above:

GPIO5_IO13, GPIO5_IO09, GPIO5_IO26, GPIO3_IO04

They are used as chip selects, so they are outputs. The one on the bank 3 is already covered but three of them are on the bank 5. I didn’t perform any changes to the device tree concerning them. Is there a way to turn off only these three pins in linux?

Btw I dont have gpioinfo commands since I started creating linux images with device tree overlays using torizoncore-builder, instead of the provided torizon image. Is there any way to add it to the image?

EDIT: I overlooked that you gave me the solution for pin 206 instead of 216. I am already using pin 206 as a chip select. I can move the interrupt pin to the 206 but then I need another gpio pin for the chipselect. Do you think one of the 216, 218, 220 or 222 GPIOs can just work as an output instead of the interrupt pin?

Hi @swiss,

Good to hear that these errors from the video are gone now.

The issue here is how the GPIO works inside the processor. The chip will control a bank of the GPIO pins, not the pins individually, so I am afraid it’s not possible to disable only these three pins, the whole bank 5 should be disabled to solve your issue (this is more a hardware problem on how things work inside the processor than a device tree issue).

We already disabled bank 3, so I would suggest you move these 3 pins to bank 3 instead of using pins from bank 5. Is that possible in your case?

I apologize, you are using Torizon. You can use these gpio commands inside a container then, please take a look at this guide on how to do it: How to Use GPIO on Torizon OS | Toradex Developer Center
Basically, you will start a container and pass the gpiochip device to it, so you will have access to these commands.

Looking at the datasheet here, disabling bank 3 you will have access to pins 206, 244, 76, 52, 54, 56, 58, 60, 62, 64, 66, 48, 46, 44, 42, 21 and 17 (SODIMM values). Can you use one of them? Otherwise, you will have to disbale another gpio bank, as previously mentioned.

Hope this helps!

Best Regards,
Hiago.

Hi @hfranco.tx ,
I have to to check if I bank 3 will be enough, I will update you on Monday.

I decided to avoid containers for now since I don’t have any experience with them. It would create me a lot of extra work without much benefits (maybe I don’t see the benefits, correct me if I’m wrong), so I can live without gpioinfo, thanks for the explanation.

Hi @swiss,

ok, then let me know if we need to change anything to work this out.

Indeed you need to learn how to deal with Docker, but since you are using TorizonCore, there are many benefits to using containers. If you have a chance, there is this webinar that explains it better: https://www.youtube.com/watch?v=MzKNm1f_43E

For the GPIO part though, it’s very straightforward, just run the command below inside TorizonCore:

# docker run --rm -it --device /dev/gpiochip0 torizonextras/arm64v8-gpiod

And you will have access to GPIO commands inside the container for bank 0. If you want to have access to all banks or change it, just edit the /dev/gpiochip0 part (or add more).

Best Regards,
Hiago.

1 Like

Hi @swiss,

just to add more information, this video should help you too: Session 06: Containers for Embedded Devices. Why? - YouTube

Best Regards,
Hiago.

Hi @hfranco.tx ,
I have one more question before commiting to changing all my GPIOs.

Taking for example SODIMM 44 and 46 that are on the bank 3 (see picture under), their highlithed (yellow) function is sai5 and not GPIO, but in the second to last columnt it says default mode ALT5, which is GPIO. Does linux device tree follow the yellow highlights or the default mode rules, i.e. should I also disable sai5 or disabling gpio3 is enough?
image|689x52

Staying on my particular use case, I guess the safest bet is to disable the QSPI on the sodimm pins 52,54…66. Then with their main function and the qspi disabled, those pins should be safe to use from the M4?

Thanks

EDIT: I started testing with the qspi pins, and I realized quickly that I had to turn off the QSPI in the device tree as well (&flexspi, as I found in the verdin dtsi file). So I guess the “default mode” column in the datasheet doesn’t mean anything when it comes to linux and that it is trial and error until you find pins that work. We are in the process of printing a new carrier board anyway, but I gotta say this peripherals management is quite a mess. I will have to take your word for it that disabling bank 3 won’t bring any problems down the line when I start developing the linux side.

Hi @swiss,

You can think of the “default mode” as the default mode for the processor. For example, if nothing is defined or no device tree is provided, the pin will be on the default mode. The highlighted yellow is what Toradex sets as default in our device tree and what you should follow to make modules compatible with each other in the same family (for example, Colibri iMX6 with iMX8X and so on…).

Take this note from the datasheet:

Below is a list of all the i.MX 8M Mini pins that are available on the SODIMM connector. It shows
the alternate functions that are available for each pin. The GPIO functionality is normally defined
as the ALT5 function. The alternate functions used to provide the primary interfaces, done to
ensure the best compatibility with other Verdin modules, are highlighted.

Therefore, you should follow the pins marked as yellow in this case. You can always check the device tree here as well to see what is the default function of the pin.

What I think is happening in your case is that you have to disable the yellow function and also the gpio3 because the GPIO inside the iMX is actually a bank of pins, so Linux is probably messing with these pins when it boots up. So I recommend you disable the bank and the yellow function (flexspi, sai5…) aswell.

Since you’re going to create your carrier board, I recommend you disable these pins and then test it inside Linux to check if it’s working or not, but I think you are already doing that.

Best Regards,
Hiago.

Hi @hfranco.tx ,
Thank you for the explanation!

Yes so far everything seems to work. I will close this topic since it is getting lengthy and open a new one if any problems occur. Thank you for your patience and support.

1 Like