SPI PCS0 control

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

SPI PCS0 control

3,265 Views
bobg
Contributor I

TWR-K60D100M Platform.

I am using the SPI sample code, spi_demo, for SPI2, which includes hal_spi.c. I am trying to set PCS0 to ‘1’ at the start of transmitting a number of bytes and to ‘0’ at the completion.

My interpretation of the code in hal_spi_transfer_one_byte(u8 v, Bool end) suggests this should already be achieved in this code, but the output remains at ‘0’. I’ve also tried specifically configuring PCS0 as a output after selecting the port as a GPIO in init_io, but to no avail.

 

u8 hal_spi_transfer_one_byte(u8 v, bool end)

{

    if(end)

        SPI2_PUSHR = //SPI_PUSHR_CONT_MASK |

                                    SPI_PUSHR_EOQ_MASK  |                   // sets bit 31 to ‘0’ to negate selected PCS after last byte

                                                                                                      //  transmitted, EOQ - Last byte

                                   SPI_PUSHR_PCS(1<<0) |                       // select PCS0

                                   (v);

    else

        SPI2_PUSHR = SPI_PUSHR_CONT_MASK |                // Maintain PCS output

                                   SPI_PUSHR_PCS(1<<0) |                     // select PCS0

                                  (v);

 

    while((SPI2_SR & SPI_SR_TCF_MASK)==0)                       // Wait until transfer complete

        ;

    SPI2_SR |= SPI_SR_TCF_MASK;

    return SPI2_POPR&0xff;

}

 

The actual SPI transmission works fine.

 

Any help to determine what I am doing wrong and why I cannot control PCS0 would be appreciated.

Labels (1)
0 Kudos
Reply
17 Replies

2,538 Views
egoodii
Senior Contributor III

PCSIS[4:0] controls the 'positive/negative logic' of the generated CS-pattern selected in PCS[5:0].  Clear PCSIS_0 and PCS_0 should become 'active high' for you.

BTW I've never understood why PCSIS apparently did NOT include control over the 6th potential CS, as in SPI0_PCS5....

0 Kudos
Reply

2,538 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi EARL GOODRICH,

   PCS0 is the peripheral chip select pin. The active state or inactive state is determined in the SPIx_MCR[PCSIS] pin.

pastedImage_1.png

So, please check these configuration at first.

Normally, when the CS pin in the transfer stage, it is low, before transfer, it is high.

 Besides, about the code, you can refer to our KSDK2.0 sample code which can be downloaded from this link:

Welcome to Kinetis Expert | Kinetis Expert

Wish it helps you!

If you still have question, please let me know!


Have a great day,
Kerry

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
Reply

2,538 Views
bobg
Contributor I

Thank you for your reply.

The PCS0 is being used to 'handshake' with an external peripheral slave SPI device to indicate start / end of SPI transmission. 

PCSIS in MCR is already set in the spi_demo code -  init_inactive_cs within hal_spi.c -

 SPI2_MCR |= SPI_MCR_PCSIS(1<<0)

which I am interpreting as PCS0 being selected and the inactive state of PCS0 as high - ie should be low during data transmission. Unfortunately it remains low before / during / after transmission.

I am monitoring B46 on the TWR-K60D100M board. 

I'll download the KSDK2.0 sample code to see if it gives 

0 Kudos
Reply

2,538 Views
egoodii
Senior Contributor III

You did not elucidate Mark's query about pin setting to 'output' and to the ALT that selects 'SPI2_PCS0' operation on that pin (and NOT calling for it to be general 'I/O').  It looks like you are using PTD11, and like most SPI-pin-function-selections for that part it means ALT_2.

0 Kudos
Reply

2,538 Views
robertgilmore
Contributor I

Sorry - in my haste I ended up only opening the last post.

I am using ALT 2 to set PTA11 to its SPI2_PCS0 functionality, same as that use in init_io in hal_spi.c in SPI demo. I had briefly, in error, tried to also add output code. 

It does not matter if PCS0 is the traditional active low output when data is being transferred or high - just need it to actually change one way or the other before and after SPI transmission of a number of bytes. 

My interpretation of the SPI_demo, is that it should be high when in the inactive state and low during the transmission. However as indicated it remains low and as far as I can see the signal, PTD11 should come out on B46 on the TWR-K60D100M - though I notice on the User Manual the SOUT an SIN pins appears to be crossed over.

Code being used: 

static void init_io(void)
{
PORTD_PCR11 &= ~PORT_PCR_MUX_MASK;   /* PTD11.*/
PORTD_PCR11 |= PORT_PCR_MUX(2);               /* ALT2 for SPI2_PCS0, B46 on TWR bd.*/

PORTD_PCR12 &= ~PORT_PCR_MUX_MASK;   /* PTD12 */
PORTD_PCR12 |= PORT_PCR_MUX(2);              /* ALT2 for SPI2_CLK, B48 on TWR bd.*/

PORTD_PCR13 &= ~PORT_PCR_MUX_MASK;  /* PTD13 */
PORTD_PCR13 |= PORT_PCR_MUX(2);              /* ALT2 for SPI2_SOUT - Output, B45 on TWR bd */

PORTD_PCR14 &= ~PORT_PCR_MUX_MASK;  /* PTD14 */
PORTD_PCR14 |= PORT_PCR_MUX(2);             /* Alt2 for SPI2_SIN - Input, B44 on TWR bd.*/
}

/*The SPI demo has the following as separate procedures, the following just shows the raw code used for setting up the SPI port, but includes my comments on what I believe is happening.*/

SPI2_MCR |= SPI_MCR_MSTR_MASK;          /* set bit 31 to '1' to select Master Mode. */

SPI2_MCR &= ~SPI_MCR_MDIS_MASK;       /* enable the module clocks.*/

SPI2_MCR |= SPI_MCR_DIS_RXF_MASK |   /* Rx FIFO is disabled.*/
                        SPI_MCR_DIS_TXF_MASK |   /* Tx FIFO is disabled.*/
                        SPI_MCR_CLR_RXF_MASK |  /* clear the Rx FIFO counter.*/
                        SPI_MCR_CLR_TXF_MASK;    /* clear the Tx FIFO counter.*/

/* My interpretation is it is this line that determines whether PCS0 is high or low when inactive, with the SPI_demo setting the inactive state to high.*/

SPI2_MCR |= SPI_MCR_PCSIS(1<<0);          /* bit 16, PCS0 = 1 - the inactive state of PCS0 is set high.*/

/* My interpretation is that this part of the code that is called when each byte is transmitted should change the state of the PCS0 output when 'end' is set when the last byte is being transmitted - whether is active low or high being determined by the MCR setting above. */ 

uint8 hal_spi_transfer_one_byte_SPI2(uint8 v, Bool end)
{
    if(end)
        SPI2_PUSHR = //SPI_PUSHR_CONT_MASK |        

                                   SPI_PUSHR_EOQ_MASK |          /* Initially set all bits to '0' apart from bit 27 = '1' to indicate

                                                                                               last data in SPI queue.
                                                                                               bit 31 is set to '0' thus PCS signal will be negated after

                                                                                               completion of the transfer of the last byte.*/
                                    SPI_PUSHR_PCS(1<<0) |          /* bit 16 for PCS0.*/
                                    (v);                                                 /* bit 15-0, add TxData.*/
else
     SPI2_PUSHR = SPI_PUSHR_CONT_MASK |         /* set all bits to '0' apart from bit 31 = '1' to keep the PCS

                                                                                             signal asserted between transfers.*/
                                SPI_PUSHR_PCS(1<<0) |              /* bit 16 for PCS0 */
                                (v);                                                     /* bit 15-0, add TxData.*/

/* Wait for a byte to be sent and read in.*/
while((SPI2_SR & SPI_SR_TCF_MASK)==0)                /* 1 when transfer complete.*/
;

SPI2_SR |= SPI_SR_TCF_MASK;                                     /* clear the TCF flag */

return SPI2_POPR & 0xff;
}

Please advise if my interpretations are not correct and what to check next.

Thank you

0 Kudos
Reply

2,538 Views
egoodii
Senior Contributor III

Your interpretations look correct.

We have been assuming here that your ONLY problem is PCS --- you see 'nice data bytes' at your expected rate rambling out SOUT, and maybe even proper 'input' data returned from hal_spi_transfer_one_byte_SPI2.  Can you 'halt' the code somewhere in hal_spi_transfer_one_byte_SPI2 and show us the value you see in PORTD_PCR11 'just to be sure'?  Also the PORTD data-direction-register at that time.

0 Kudos
Reply

2,538 Views
bobg
Contributor I

With a break-point on the SPI2_PUSHR, the Register values are:

      PORTD_PCR11 = 0x00000200

      GPIOD_PDDR   = 0x00000000

The output from the SPI looks credible - with the frequency correct and individual bytes changing with the data patterns - though not set up the other side yet to fully check. I've not checked the receive side yet either.

0 Kudos
Reply

2,538 Views
egoodii
Senior Contributor III

Well, I'm sorry to say that I don't see anything amiss in the code operations (assuming that at some points hal_spi_transfer_one_byte_SPI2 is called with a non-zero second parameter), and 'nobody' has clobbered PORTD_PCR11 on you.   That mux-control, and the SPI 'MSTR' bit, should be enough to configure that pin as a SPI2 CS0 output...

A couple random comments:

I never had 'good luck' using the EOQ bit -- not even sure why this driver SETS that bit.  I was trying to use it for a one-bit 'FIFO empty' indication.

The 'or equals' of:

SPI2_SR |= SPI_SR_TCF_MASK;

is a bit misleading and inappropriate.  In interrupt-status registers, such an operation will read ALL the 'active' flag bits, and the write-back will clear ALL such active flags in one go, NOT just TCF as the operation might indicate.  In this particular case, I don't think you CARE about any of the other flags, so this shouldn't be an 'issue'.

0 Kudos
Reply

2,537 Views
bobg
Contributor I

Tried reconfiguring PTD11 as an output to ensure I could toggle that under my control – no issues found.

I tried using SPI0 to see if there was any difference – but the PCS0 output is doing the same on both SPI0 and SPI2 - remaining low.

0 Kudos
Reply

2,538 Views
mjbcswitzerland
Specialist V

Hi

I have attached a binary that can be loaded to the TWR-K60D100M board that will try to find an SPI Flash device on the same pins as you use. After each reset there will be some activity where the CS line is controlled automatically.

Note that if the CS line is correctly configured it will be at '1' in the stable state (before doing anything in SPI2). If it isn't there is a bad configuration or the measuerment points are not good. The attached binary will enable ensuring that the measurement itself is not bad.

The code is as follows (as reference since it uses different methods to you which are however more fool-proof, yet should be just as easy to follow).

// Pin configuration
//
POWER_UP(3, SIM_SCGC3_SPI2);
_CONFIG_PERIPHERAL(D, 11, (PD_11_SPI2_PCS0 | PORT_SRE_FAST | PORT_DSE_HIGH));
_CONFIG_PERIPHERAL(D, 12, (PD_12_SPI2_SCK | PORT_SRE_FAST | PORT_DSE_HIGH));
_CONFIG_PERIPHERAL(D, 13, (PD_13_SPI2_SOUT | PORT_SRE_FAST | PORT_DSE_HIGH));
_CONFIG_PERIPHERAL(D, 14, PD_14_SPI2_SIN);
// SPI configuration
//
SPI2_MCR = (SPI_MCR_MSTR | SPI_MCR_DCONF_SPI | SPI_MCR_CLR_RXF | SPI_MCR_CLR_TXF | SPI_MCR_PCSIS_CS0 | SPI_MCR_PCSIS_CS1 | SPI_MCR_PCSIS_CS2 | SPI_MCR_PCSIS_CS3 | SPI_MCR_PCSIS_CS4 | SPI_MCR_PCSIS_CS5);
SPI2_CTAR0 = (SPI_CTAR_DBR | SPI_CTAR_FMSZ_8 | SPI_CTAR_PDT_7 | SPI_CTAR_BR_2 | SPI_CTAR_CPHA | SPI_CTAR_CPOL); // for 50MHz bus, 25MHz speed and 140ns min de-select time
// First byte transmission (byte is the value to send)
//
SPI2_MCR |= SPI_MCR_CLR_RXF; SPI2_SR = (SPI_SR_EOQF | SPI_SR_TFUF | SPI_SR_TFFF | SPI_SR_RFOF | SPI_SR_RFDF); // flush FIFO and reset flags
SPI2_PUSHR = (byte | SPI_PUSHR_CONT | SPI_PUSHR_PCS0 | SPI_PUSHR_CTAS_CTAR0);

// Final byte transmission (byte is the value to send) after which the CS will negate
//
SPI2_PUSHR = (byte | SPI_PUSHR_EOQ | SPI_PUSHR_PCS0 | SPI_PUSHR_CTAS_CTAR0);

This is the complete code to configure and send a couple of bytes.

The waveform is shown below.

pastedImage_1.png

Regards

Mark

Professional support for Kinetis: http://www.utasker.com/index.html
Remote desktop one-on-one coaching: http://www.utasker.com/services.html
Getting started to expert videos: https://www.youtube.com/results?search_query=utasker+shorts

0 Kudos
Reply

2,538 Views
bobg
Contributor I

I managed to download the BIN File, thank you: I was able to load and program using the bin file. Although PCS0 output inactive state was ‘high’ there was only a couple of negative transients and no SCK pulses, thus not getting any SPI transmission when using the BIN file.

0 Kudos
Reply

2,538 Views
mjbcswitzerland
Specialist V

Robert

I test the same binary on my TWR-K60D100M board in the tower with SER card and measure the waveforms as in the screen-shot after each reset.

It sounds as though you get the CS signal (asserts negative) which means that the CS line is essentially OK.

If you don't get the clock signal you must have a problem with the connection or the measurement.

Since the CS line does operate (the main topic) the HW is Ok with respect to this so you should be able to get your code to do the same.

Regards

Mark

0 Kudos
Reply

2,538 Views
bobg
Contributor I

There is no SPI device on the TWR-SER module. The SPI Flash is on the TWR-MEM module, which unfortunately I do not have for checking for any responses. At the moment my setup is purely setting the SPI as a master which will be transmitting to an external SPI slave which in practice will be a component embedded within a FPGA - which is not available yet. 

The design also required added delays between the PCS0 being asserted (low) and the 1st SCK pulse, and also between the last SCK clock pulse and PCS0 being negated (high). It is the Tasc value that was causing the issue, due to my entering the wrong bit value of ASC resulting in an inordinately long delay resulting in the appearance of PCS0 being low all the time.

The above was also not helped by, for whatever reason, the Tcsc and Tasc both being twice as long as expected - something else to investigate, but at least I can change them which is the main thing.

Thank you for your help and patience in helping me to solve the PCS0 issue. 

0 Kudos
Reply

2,538 Views
mjbcswitzerland
Specialist V

Robert

The binary sets the CS and SCK irrespective of what is connected to it. I also have no TWR-MEM board - I just measured the signals on the backplane.......

Regards

Mark

0 Kudos
Reply

2,538 Views
bobg
Contributor I

I tried to unzip the file, but all I am getting is an empty directory with the name of the bin file.

Bob

0 Kudos
Reply

2,538 Views
mjbcswitzerland
Specialist V

This forum automatically zips attachments and I don't have any problem unzipping. Maybe your zip tools are not compatible(?)

I put it on a different server for you:
http://www.utasker.com/temp/uTaskerV1.4.12_TWR-K60D100M_SPI-Flash.bin

Regards

Mark

0 Kudos
Reply

2,538 Views
mjbcswitzerland
Specialist V

Robert

You need to configure the CS pin in question to its CS peripheral function and not to an output.

The CS output uses negative logic (it asserts to '0') and I don't thin that this can be changed so you may not be able to use it if you need to generate '1'.

You can also directly control the CS line as a port output if its automatic CS control is not suitable.

Regards

Mark

0 Kudos
Reply