Can SODIMM 184 be used as a GPIO in the Colibri iMX6DL?

We are using pin 184 as a GPIO on a carrier board where we are transitioning from the Colibri T20 to the Colibri iMX6DL. It mostly works with the iMX6, but every now and again the output goes low due to something other than our software. Often it goes low within a microsecond or two after I set it high. When this happens the pin config looks normal in the GPIO config tool.

I found this post which states that pin 184 cannot be used as a GPIO with the Colibri iMX6ULL. Does this apply to the Colibri iMX6 as well? Do I just need to avoid using pin 184?
Pinout Clarification for Colibri SoM i.MX6ULL - Technical Support - Toradex Community

The datasheet for the Colibri iMX6ULL does contain warnings about pin 184, but the datasheet for the Colibri iMX6DL does not.

Hi, I’m the Toradex AI Assistant. The Toradex Support team will follow up with you shortly!

Did you like my answer?

:+1: :-1:


Based on the provided context, it appears that pin 184 has specific restrictions when used as a GPIO on the Colibri iMX6ULL, but there is no explicit mention of such restrictions for the Colibri iMX6DL in the datasheet.

However, given that you are experiencing issues with the pin going low unexpectedly on the Colibri iMX6DL, it is possible that there might be some underlying hardware or software behavior affecting this pin.

Here are a few steps you can take to troubleshoot and potentially resolve the issue:

  1. Check Pin Multiplexing: Ensure that pin 184 is correctly configured as a GPIO in your device tree or board configuration files. Incorrect pin multiplexing can cause unexpected behavior.

  2. Electrical Characteristics: Verify the electrical characteristics and ensure that there are no conflicts or external factors causing the pin to go low.

  3. Software Configuration: Double-check your software configuration to ensure that there are no other processes or interrupts that might be affecting the pin state.

  4. Errata and Known Issues: Review the Colibri iMX6DL errata and known issues documents to see if there are any documented issues related to pin 184.

  5. Alternative Pin: If the issue persists and you cannot find a resolution, consider using an alternative GPIO pin that does not exhibit this behavior.

Since the datasheet for the Colibri iMX6ULL contains warnings about pin 184, it might be prudent to avoid using this pin if you continue to experience issues, even though the Colibri iMX6DL datasheet does not explicitly mention such restrictions.

If you need further assistance, you can contact Toradex technical support for more detailed guidance specific to your use case.

Please, also check if these links can help you solve your problem:

https://community.nxp.com/pwmxy87654/attachments/pwmxy87654/imx-solutions%40tkb/339/2/colibri_arm_som_imx6_datasheet.pdf.

I tried disconnecting the Ethernet cable from the carrier board to see if that would cause the PHY to shut-down and solve the contention on pin 184. I think that might have had stopped the problem from happening, but I only ran a short test. This might support the conclusion in the other topic I linked to. We do need to use Ethernet though, so I think I probably do just need to use a different pin. Are there any other pins which are affected in the same way?

SODIMM pin 184 on the Colibri iMX6DL does not have a specific function and can be used as a regular GPIO. Please double-check that your setup or application is not using it as a CAN transmit pin.

If you have any further questions, please remember to specify the WinCE version and BSP release version you are using

@alex.tx I’m using WinCE image 1.8 and BSP version 2.6

I think I’ve found the root cause. I found that pin 184 behaves perfectly well if I set it or clear it using the GPIOconfig tool without having my firmware running. That made me believe that pin 184 can be used as a GPIO in the Colibri iMX6DL, as you just confirmed in your last message.

On a hunch I wondered if the GPIO library is not thread-safe so I added a mutex to protect calls to Gpio_SetLevel() and Gpio_GetLevel(). Our firmware only sets and clears pin 184 from a single thread, but we have other threads which use other GPIO pins at the same time. Adding a mutex appears to solve the problem, but I need to perform a longer-term test to confirm that the problem is really solved. I’m concerned about the performance impact of having to use a mutex, although I have not yet measured what that impact might be.

After testing the addition of a mutex I found this relevant post, which contains a comment from you saying that the GPIO library is thread-safe on the T20 but not on the iMX6. That would explain why we don’t see this issue when we use a T20 on the same carrier board running the same firmware, but we do see this issue now that we are migrating to the iMX6.

I have a few questions:

  1. Is Gpio_GetLevel() thread-safe? My guess is that the non-atomic process is setting and clearing a bit in the GPIO control register, which would mean that reading a bit from that register is safe to do. I am currently running an experiment where I only use a mutex to protect Gpio_SetLevel() and that seems to suggest that Gpio_GetLevel() does not need to be protected.
  2. I’m guessing that the problem only occurs when accessing GPIO pins in the same GPIO bank from different threads. If that is true then it might be more efficient to use a set of mutexes to protect access to the banks individually, rather than using a global GPIO mutex. Is my guess right?
  3. If I should protect GPIO banks individually then could you share a link to a document which maps SODIMM pin numbers to GPIO bank numbers? I’m sure I have seen a document like that on the Toradex web site but I can’t find it now.
  4. We also use the iMX6 with Torizon. It sounds like the non-atomic behavior is a hardware register issue, in which case the Torizon GPIO driver must have the same issue. Is the GPIO driver on Torizon also not thread-safe, or does Linux already add a mutex to protect us?
  5. On the iMX6 we can use any GPIO as the chip select with the SPI driver. That makes me think that on the iMX6 the Spi_Read() function uses Gpio_SetLevel() internally. Is that true? If it is then I would need to protect my calls to Spi_Read() with the same mutex that I use to protect Gpio_SetLevel()
  1. Yes, the Gpio_GetLevel() function should be thread-safe.
  2. Technically, yes. If one thread modifies one GPIO bank while a second thread modifies another bank, you will not encounter any issues. Although the Gpio_GetLevel() function is quite short—it just reads a 32-bit GPIO register, flips a bit, and writes it back—a global mutex on that function shouldn’t significantly affect performance.
  3. Details about the pin-to-GPIO bank/IO number relation are listed in Table 11 SODIMM Pins of the Colibri iMX6 datasheet.
  4. I can’t comment specifically on the Linux GPIO driver, but the source code is open, so you can check it yourself.
  5. No, the Spi_Read() function does not use Gpio_SetLevel(). However, the approach for toggling the CS pin is the same: read the GPIO bank, modify it, and write it back.

Hi @alex.tx,

I thought I should add an update on this topic as I’ve been working hard on this over the last week. The failure rate is quite low already so it takes about 8 hours of run-time to collect enough statistics to know if each change has helped or not. I did add an array of CRITICAL_SECTION objects, one for each GPIO bank. That does help significantly. I chose to use CRITICAL_SECTIONs as they are faster than mutexes, and I don’t need the more sophisticated features of mutexes like a time-out in this case.

I found that the library functions Spi_Read() does indeed access the GPIO control registers if a chip select line is assigned to the SPI port, and that this is not thread-safe. So, I changed my code to drive the chip select as a GPIO via my new function which is protected by CRITICAL_SECTIONs and that also reduced the GPIO failure rate significantly.

Although these changes reduced the GPIO failure rate significantly, they did not reduce it to zero. I spent many days trying to find the remaining problem and couldn’t do it. In the end I found that adding a retry of Gpio_Set() inside the block protected by the CRITICAL_SECTION did the trick. It seems that only 1 retry is ever needed, and the code works without having to retry most of the time. The code is something like this:

void SetLevel(uIo io, tIoLevel val)
{
   EnterCriticalSection(&criticalSection);
   Gpio_SetLevel(hGpio, io, val);
   if (Gpio_GetLevel(hGpio, io) != val)
   {
      Gpio_SetLevel(hGpio, io, val);
   }
   LeaveCriticalSection(&criticalSection);
}

I would rather be able to fully understand the root cause and fix it properly, as this solution feels like an ugly patch. But it does work. Perhaps I’ll come back later and try again to get to the real root cause, it might be somewhere else in the Toradex libraries or somewhere else in my own code.