Hello,
I am trying to interface a SPI NOR flash (slave) to my i.MX6 (master). My device requires that the CS be held for the entire transaction (cmd byte + N data bytes returned from the device), however when I observe the spi transfer on my logic analyzer I noticed that the i.MX6 releases CS between each data word. My device will not shift out its data in this case.
I should mention I am using spidev, and that I've tried setting cs_change in the spi_transfer and that had no effect... Looking in spi_imx.c I don't see where the cs_change parameter is ever used.
It appears from the code in spi_imx.c that the ecspi controller should be set up todo a single burst transfer for the bus I am using (ecspi3) as shown in figure 21-8 of the IMX6DQRM. However I am seeing behavior more like figure 21-9 on my logic analyzer even though SS_CTL[3:0] is appears correct and SMC is cleared. So I don't understand whats going on at this point.
Can some i.MX6 spi expert chim in?
Thanks,
Jeff
已解决! 转到解答。
I figured out what my problem was. In addition to setting up SS_CTL correctly, I also needed to configure the burst length in CONREG as well. I had to define the total number of bits in a single transfer. The driver only sets bits [24:20] in CONREG; however for single burst the total number of bits in the transfer needs to be set. Now I see the CS held the entire transaction and the device shifting out data as expected.
I've modified the driver to take cs_change into account now and configure single burst mode or multi burst mode based on it.
After double checking I noticed that SS_CTL is always getting set to multi burst mode for any device. I modified the driver so SS_CTL was set to single burst mode but when I perform a transaction now the driver hangs up. Any Ideas?
Thanks,
Jeff
I assume you are using the ioctl() calls like in spidev_test.c (https://raw.github.com/torvalds/linux/master/Documentation/spi/spidev_test.c) to interface to spidev? cs_change must be cleared in spi_ioc_transfer struct in order for single burst mode to work. Most likely spidev ioctl handler is hanging because of this. Can you try this? Clearing cs_change in spi_transfer may not work because the spi_ioc_transfer code may override it (just for my curiosity, where did you set cs_change in spi_transfer struct - i.e what file and function?).
for an example, look here:
I doubled checked and I was indeed setting cs_change=0. Here is a snippet from my code where I setup the transfer:
Here is a ss of when it hangs.
I would recommend to probe the ecspi status register (ECSPIx_STATREG ) when it hangs to see the Rx/Tx status in the two cases (SS_CTL set vs cleared). This may shed light on what to do to fix the spi_imx driver. You are correct, in that this file does not use the cs_change parameter.
There is a devregs program from here that you can use to probe the imx6 registers from user space (its for imx5 but applies to imx6 as well): http://boundarydevices.com/i-mx5x-device-register-access/.
I've added the ECSPI reigsters in my forked git repo. Its here: VarsMolta/imx-utils · GitHub
I figured out what my problem was. In addition to setting up SS_CTL correctly, I also needed to configure the burst length in CONREG as well. I had to define the total number of bits in a single transfer. The driver only sets bits [24:20] in CONREG; however for single burst the total number of bits in the transfer needs to be set. Now I see the CS held the entire transaction and the device shifting out data as expected.
I've modified the driver to take cs_change into account now and configure single burst mode or multi burst mode based on it.
Here is a patch with my changes to the spi_imx driver. I've have only tested it with an M25P64 NOR SPI flash, as that's what we're using in our system. Currently I have only added support for 8 bpw. Based on limitation in the spi controller your limited to 4096 bits per single burst transfer. I left most the original driver code in place, the difference being it only gets called when cs_change =1, otherwise it sets up a single burst transfer.
Hi Jeffrey,
have you updated your patch against kernel 3.10.17 coming with Yocto? I need a SPI single burst feature because I've a SLIC chip which require CS asserted as per 8bit transfer.
Thanks in advance.
Hi Jeff,
I enabled the spi device in the kernel config and it did show up in the /sys/.. directory but not in /dev
can you give me some tips how to add the spi device correctly?
Thanks
Robert
Hi Robert,
I assume you mean you enabled user land SPI support in the kernel? So you expecting somthing like /dev/spidevx.y? If so then you need to add an entry in your board descriptor for spidev, as the spidev driver doesn't dynamically register this with the kernel.
In the board descriptor file for your platform (found under arch/arm/mach-mx6 for the i.mx6), you need to add spidev entry like the following:
static struct spi_board_info imx6q_spi_device[] __initdata = {
{ | |
.modalias = "spidev", | |
.max_speed_hz = 48000000, /* max spi clock (SCK) speed in HZ */ | |
.bus_num = 2, | |
.chip_select = 0, | |
.mode = SPI_MODE_1, |
},
}
static int imx6q_spi_cs3[] = {
IMX6Q_ECSPI3_CS0,
};
static const struct spi_imx_master imx6q_spi_data3 __initconst = {
.chipselect = imx6q_spi_cs3,
.num_chipselect = ARRAY_SIZE(imx6q_spi_cs3),
};
There should be a spi_init function where you add the spi device. Again this depends on your platform but they should all be roughly the same. Most will already have a configuration for some sort of on board spi nor flash you can use as an example.
You may also need to configure the iomux depending on your platform, in mine I had to setup the chip select for the spi controller I was using.
Other good sources of information:
https://www.kernel.org/doc/Documentation/spi/spi-summary
https://www.kernel.org/doc/Documentation/spi/spidev
Hope this helps.
Jeff
hi jeff,
yes, absolutly right.
i managed it to get the driver visible in /dev.
but thank you very much for the answer.
yesterday this 'thing' got me nailed down.
your patch is also very interesting as we are to build communication gateways using spi.
what about:
static const ...
makes shure it is in flash space not ram.
best
robert
Glad you got it working. I'm not sure what your platform is or whether its custom hardware, but I would avoid using the spi controllers cs select if possible and instead use a GPIO. Using the i.MX6's spi controller in single burst mode is very painful. On our board the vendor did this with their spi flash, but as I am using another spi controller connected to the Q7 signals, I was stuck with it and had no choice.
Not sure what flash, static const would ensure? What if you have an SD card and no flash?
Hi Jeff, Roberto,
> avoid using the spi controllers cs select if possible and instead use a GPIO
I'm in a similar situation. But I think it is complex, because it looks like you can't trivially use SPI_NO_CS with imx_spi , _and_ spidev requires a working imx_spi which requires a valid chipselect. I'm going to try giving it a dummy chipselect and see if I can make it work even without SPI_NO_CS set in the userspace mode.
Thanks,
jaya
Hi,
I used spidev_test.c as my starting point, I have not tried to write a protocol driver yet as I'm hoping to get spidev working first. I was already setting cs_change to 0 explicitly (even though the memset should take care of this) after I create the spi_transfer struct. I will double check my settings and rerun my test and update this thread. I did not see where in spi_imx.c this flag ever got used as the driver appears to always configure the controller for multi burst.
Thanks
Jeff