MCF547x/8x DSPI and 16-bit transfers

cancel
Showing results for 
Search instead for 
Did you mean: 

MCF547x/8x DSPI and 16-bit transfers

1,191 Views
pmatil
Contributor I

Hello,

 

I'm trying to interface an RTC chip into my MCF5485 board, It's on the SPI bus, on chip select 0. The RTC chip is an RTC9701JE, for which there's a driver in the kernel: rtc-r9701. The problem is that the chip doesn't initialize. I have observed the traffic on the SPI bus using a logic analyzer and from there I can see that the SPI deasserts the chip select between bytes even though it should transfer 16bits at a time. The RTC chip expects a 16bit transfer and a continuous chip select for the entire 16bits. Currently the system transfers 8bits, deasserts the CS and after 30 ms asserts it again and tries to read 8bits but obviously can't get any usable data in. I'm using latest Freescale's BSP to build the kernel and root file system.

 

The question is: how do I modify the driver so that the chip select is continuously asserted during transfers? I have set 16bit transfers (devices.c) but still it transfers 8bits at a time?

 

I have modified devices.c to load the driver, like so:

 

#ifdef CONFIG_RTC_DRV_R9701

static struct coldfire_dspi_chip rtc_spi_chip_info = {

    .bits_per_word = 16,

    .mode = SPI_MODE_3,

    .pcsis = 0x00, // All chip selects active-high (idle-state low = 0x00)

    .dbr = 0,

    .pbr = 3,

    .br = 6,

    .pcssck = 2,

    .pasc = 2,

    .pdt = 2,

    .cssck = 2,

    .asc = 1,

    .dt = 1,

};

#endif

 

#if defined(CONFIG_RTC_DRV_R9701)

    {

      .modalias = "rtc-r9701",

      .max_speed_hz = 1000000,

      .bus_num = 1,

      .chip_select = 0,

      .controller_data = &rtc_spi_chip_info,

    },

#endif

 

The driver loads but the probe fails as it tries to read a register in the RTC and can't get the correct data. I have tried to set the CONT bit in the DTFR register but I needed to write some code into the mcf_dspi.c and it didn't seem to work. No errors in the compilation either.

 

Attached are a couple of pics and also the drivers rtc-r9701.c and dspi_mcf.c.

 

transfer1.png: this is the first byte transferred. The write is correct, 0x87.

 

transfer2.png: after 33 ms it tries to read back (writes 0x00) but fails to read any valid data.

 

transfer3.png: this is how it should go. Write 0x87 and then during the next 8 clocks the data is read from DI (0x20 which is correct). The difference here is that the chip select is NOT deasserted betweeen bytes. For this picture I added a 0x00 byte to transfer in addition to 0x87. The problem is still that after 33 ms (chip select down) it tries to read during 8 clocks and so ignores the already received correct byte. I've checked the FIFO, it reads 0xF020. 0xF0 is the bogus byte and 0x20 the correct one. So the received byte is there, the system just ignores it. Thanks in advance!

Original Attachment has been moved to: dspi_mcf.c.zip

Original Attachment has been moved to: rtc-r9701.c.zip

Labels (1)
Tags (4)
0 Kudos
7 Replies

792 Views
TomE
Specialist I

> The RTC chip is an RTC9701JE,

Last-time-buy for that from Epson closed in February 2011. Is there an alternate supplier or equivalent? Do you have guarantees of long term supply?

http://www5.epsondevice.com/en/quartz/tech/discon/mfend.html

I've downloaded the "Datasheet" from the "Discontinued Product Page" at Epson. It is a one-page overview with no useful information at all (like register list and contents). How do you get a real data sheet for this thing?

There are "implications" that it is a 16-bit chip (the 16-bit EEPROM in the block diagram for instance).

But I'd still recommend having the SPI run 8 bit transfers. The interface from the RTC driver may not support anything else.

I'd far prefer a supported current chip from a US manufacturer.

Tom

0 Kudos

792 Views
pmatil
Contributor I

Hi Tom,

Thanks for your answers. Yes the RTC chip is obsolete but we're using it for now. The datasheet doesn't tell much, you'd have to search for application manual for it. It has the timing diagrams etc. (that's where my screenshot was from). As for the EEPROM part it requires even longer transfers than 16bit but I'll ignore that part for now.

I have investigated some other SPI RTCs too, like the MAX6902 whose driver the 9701's is based from. It's using 8bit transfers too and nothing else so as you said it's the dspi_mcf that should do the continuous transfer. I'll look into that too.

Also, I did some testing last week. I transferred 16 bits (16bit mode, 2 bytes, 0x8700). MISO got the correct data (see transfer3.png), 0x20 BUT the FIFO at MBAR+0x8A7C (DRFDR_0) shows (lower 16 bits): 0xF020. I can't figure out where that 0xF0 comes from. The logic analyzer shows only my intended transfer and 0x20 as received data. You said you know about the h/w, so should I clear the FIFO before transferring or what?

P.S. I see that transfer3.png is missing from the post above. I hope it gets attached this time.

0 Kudos

792 Views
TomE
Specialist I

> BUT the FIFO at MBAR+0x8A7C (DRFDR_0) shows (lower 16 bits): 0xF020.

> I can't figure out where that 0xF0 comes from.

Neither can I. From that trace you should be getting 0xff20. It is likely the pin is floating at this time and your logic analyser and the MOSI pin have different ideas on what voltage "1" and "0" are, or they weren't the same capture.

Back to basics. At the bottom and on the wire, with SPI you shift one bit OUT and shift one bit IN at the same time. At a higher level you may be dealing in bytes, in 12 or 16-bit commands.or with a whole complicated protocol. You may be writing and reading a byte at a time, using FIFOs, rings or DMA, but the wire doesn't know and doesn't care. Frankly, all the complicated stuff gets in the way of getting it working.

So when you're sending a "read command" out, you can't stop the hardware from shifting a byte into the FIFO at the same time, and you can't read the results back in without shifting something out.

With some RAM or EEPROM chips, as long as you keep clocking, it will keep providing the next byte of data in the memory. So there's no fixed limit to how long an SPI sequence can be.

So it is "drop chip-select, shift out N bits while shifting in N bits, lift chip select". "N" can be between 1 or 4 or more usually 8 and a few million if you're reading an SPI boot ROM. You then get to make sense of the returned bits - in your case you throw the first one away and read the second one.

But the code in rtc-r9701.c is smart enough to know how to do that already. A call to it to "read the time" will have it perform SPI driver calls to generate the right bit streams on the wire and interpret the results properly.

But only if you get the configuration set up the way it expects it to be, which is probably byte-wise. Why? Because that works on any hardware. Not all SPI drivers can handle bit lengths other than multiples of 8.

In the DSPI, each entry written to the transmit FIFO can send between 4 and 16 bits. As a consequence, the receive FIFO will fill at the rate of one receive FIFO entry per transmit entry, with between 4 and 16 valid bits in it. The receive FIFO is 32 bits wide, but only 16 bits are valid, and only four bits may contain data if that's how many you sent. This isn't clear in the documentation.

Tom

0 Kudos

792 Views
pmatil
Contributor I

Hi Tom,

I've succesfully modified the rtc-r9701.c driver and spi.c to read the time and date correctly. Now the reading is done in a single SPI message without deasserting CS in between. Every time a register is read, it transfers the byte and a null byte. After that the wanted data is in the FIFO. I read only the second byte from the fifo and ignore the first. It works and as I don't know how to modify the driver any further I'm leaving it as it is. Thanks for all your help!

0 Kudos

792 Views
TomE
Specialist I

I'm not familiar with the Linux drivers, but I know a bit about the hardware.

Unless it is a 16-bit peripheral you shouldn't be setting it in 16-bit mode.

The RTC driver source looks like it expects the chip to be accessed with 8-bit transfers. That is what it is asking the other driver for.

The DSPI hardware can be configured to deassert the chip-select signal between bytes or to leave it asserted. This is controlled by the DFTR_CONT bit. That always seems to be set unless "drv_data->cs_change" is set. You might want to chase that if going back to 8-bit doesn't work.

After 33ms? It should be performing the two transfers pretty much back-to-back in the same call. You may have to start adding printk() statements to both drivers if it isn't obvious from reading the code what they're trying to do.

Good luck.

Tom

0 Kudos

792 Views
pmatil
Contributor I

Hi Tom,

Thanks for the answer. We have another embedded OS using the same board and RTC and it is using 16bit transfers as described in the rtc9701 datasheet (see the attached pic from rtc9701 datasheet). For that we are using 16bit transfers but NOT the continuous mode and it's working just fine. I have also observed the DSPI registers through the coldfire's debug interface.

You're right that the RTC driver seems to use 8bit transfers, why I don't know. As the RTC  driver is generic to linux kernel I think the difference is in the dspi_mcf driver interface. As you may have seen from the attached source, I have added the DTFR struct in the beginning of the file and tried to set the CONT bit but so far it doesn't seem to work.

So, a couple of questions:

- "That always seems to be set unless "drv_data->cs_change" is set". How did you find out that it always seems to be set? How do I set the drv_data->cs_change? BUT there seems to be this symbol MCF_DSPI_DTFR_CONT that is set if the drv_data->cs_change is set... Also do you have any idea what that void_write_data byte is? It's configurable in the devices.c.

- "...if going back to 8bit doesn't work" So you think I should configure 8bit transfers and try to get the CONT bit set?

I have already a number of printk's in the code (you may have seen them in dspi_mcf.c), but the dspi_mcf driver is a bit over my head as for how the transfer is actually happening.

0 Kudos

792 Views
TomE
Specialist I

My experience is with a non-Linux system running on an MCF5329. it has a similar (but different) QSPI module. We're running 8-bit and 16-bit peripherals, and as we write the whole low0level driver we can switch the QSPI between 8 and 16 bit messages very easily. I don't have Freescale's Linux and I don't have any MCF54xx systems.

In your case you have to do what the RTC driver expects, and it would be written to work with as many SPI drivers and hardware variations as possible. Many of them may only support 8-bit, so that's the lowest common denominator (pun intended).

As long as the hardware has the "continuous" capability you can send as many bits as you like with any controller, with the limitation that some only allow multiples of 8 bits. With some hardware the chip-selects are GPIO pins, so the software is in control of how many bytes are sent with the chip-select low. So I'm saying that using "bytes and continuous" is the most general solution to longer transfers, so that's what you should expect to find.

> How did you find out that it always seems to be set?

By searching for constant names, seeing what variable it is written to, searching for references to that variable, where it is set from and then following that one. And so on. This only gets you so far before you need working hardware and print statements. You seem to be well on the way to that.

I suspect the driver is so complicated because of the queueing. It may be asked to send a message (with CS continuously asserted) that is LONGER than its queue. It then has to somehow send the first part and leave the CS asserted, and only tell the hardware to deassert after the last byte in the last part has been sent. I suspect that's what that code is about.

> the dspi_mcf driver is a bit over my head

Dig in. You're the only one who can solve this unless another poster has a worked solution. Does Freescale have any similar chips on their development board? You're looking for the minimum modification to their code to get your one working rather than trying to work it our from scratch.

Good luck, I can't help any further.

Tom

0 Kudos