- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
I would like some help to set up or correct my SPI communication.
I've been looking for two days now and trying to make changes in vain and I don't know if the problem is in the pin configuration or in the SPI functions.
Here is a summary of my situation:
I use a PIC16LF18446 (running at 8Mhz = 32Mhz/4) and a CY15B104Q-LHXI memory purchased from Mouser. I try to read the device ID but I only get 0 or F depending on whether the pin RC2 = SDI1 is in analog or digital mode. I also tried to write a value to an address and read it but this is not conclusive. Notation : nXX = XX_bar for the XX with the bar above.
Nevertheless, my pin configuration is as follows:
Memory <= 400kHz => PIC | Configuration (* = requested in the documentation of the PIC) |
---|---|
SO <=> SDI1 = RC2 | as Input*, digital, weak pull-up disable, open-drain |
nCS <=> nSS1 = RB4 | as Input*, digital, weak pull-up disable, push-pull |
SI <=> SDO1 = RB5 | as Output*, digital, weak pull-up disable, push-pull |
SCK <=> SCK1 = RB6 | as Output*, digital, weak pull-up disable, push-pull |
Is this sounds correct?
Then, the SPI modes described in the PIC do not match those in the memory. With the information from both sides, I deduced that:
PIC-Mode | 0 | 1 | 2 | 3 |
---|---|---|---|---|
CKP | 0 | 0 | 1 | 1 |
CKE | 1 | 0 | 1 | 0 |
Memory-Mode | 0 | 3 | ||
CPOL | 0 | 1 | ||
CPHA | 0 | 1 |
I set myself in the PIC-mode 1 configuration in order to be in Memory-mode 0 and I force the SCK to be at zero to detect mode 0 when nSS1 is set to LOW. This is converted to :
SSP1STAT = 0b 0000 0000 ; // Mode 0 with sampled at the middle
SSP1CON1 = 0x2A
SSP1CON2 = 0x00
Is this configuration sounds correct?
Now, here is my code:
In the file main.c
En-tête 1 |
---|
#include <xc.h> #include "./mcc.h" #include <string.h> // Prototype ----------------------- void print_bytes(void *ptr, int size); void main(void) { PMD_Initialize(); PIN_MANAGER_Initialize();
printf("\n=== SPI 25.04 TEST ===\n\n"); __delay_ms(2000);
// Write at 0x012345 the value 0xAB, then read this latter uint8_t ReadBuffer = 0x01; uint8_t WriteBuffer = 0xAB; uint8_t DummyBuffer = 0x00; long addresse = 0x00012345; uint8_t add_0 = (uint8_t)(addresse>>0); uint8_t add_1 = (uint8_t)(addresse>>8); uint8_t add_2 = (uint8_t)(addresse>>16); uint8_t add_3 = (uint8_t)(addresse>>24); spi1_Initialize(); __delay_ms(2000); printf("\n\n=== WRITING ===\n\n"); printf("Step 1: Send WREN \n"); SS1_bar_SetLow(); // nCS à 0 DummyBuffer = spi1_exchangeByte(SPI_WREN); SS1_bar_SetHigh(); // nCS à 1 printf("Step 2: Send WRITE \n"); DummyBuffer = spi1_exchangeByte(SPI_WRITE); printf("Step 3: Send the addresse\n"); DummyBuffer = spi1_exchangeByte(add_2); DummyBuffer = spi1_exchangeByte(add_1); DummyBuffer = spi1_exchangeByte(add_0); printf("Step 4: Write the value\n"); DummyBuffer = spi1_exchangeByte(WriteBuffer); SS1_bar_SetHigh(); // nCS à 1 printf("\n=== WRITING DONE ===\n"); printf("\n\n=== READING ===\n\n"); printf("Step 2: Send READ \n"); SS1_bar_SetLow(); // nCS à 0 DummyBuffer = spi1_exchangeByte(SPI_READ); printf("Step 3: Send the address\n"); DummyBuffer = spi1_exchangeByte(add_2); DummyBuffer = spi1_exchangeByte(add_1); DummyBuffer = spi1_exchangeByte(add_0); printf("Step 4: Read the value\n"); ReadBuffer = spi1_exchangeByte(DummyBuffer); SS1_bar_SetHigh(); // nCS à 1 printf("\n=== READING DONE ===\n"); printf("RB=%2X\n",ReadBuffer); print_bytes(&ReadBuffer, 1); } // End of main void print_bytes(void *ptr, int size) { unsigned char *p = ptr; int i; for (i=0; i<size; i++) { printf("%02hhX ", p); } printf("\n"); } |
In the file spi.c (generated with the help of the MCC of MPLAB IDE and with my modifications):
En-tête 1 |
---|
#include <xc.h> #include "pin_manager.h" #include "spi_MCC.h" #pragma warning disable 520 uint8_t dummy = 0; void SPI_Read_Device_ID(uint8_t *data) { dummy = SSP1BUF; // Clear Tx buffer
// RDID opcode //SS1_bar_SetLow(); // nCS à 0 dummy = spi1_exchangeByte(SPI_RDID); // Take only the fisrt byte of the device ID data[0] = spi1_exchangeByte(dummy);
// To read the device ID //spi1_exchangeBlock(data, SPI_DEV_ID_LENGTH);
SS1_bar_SetHigh(); // nCS à 1 } void spi1_close(void) { SSP1CON1bits.SSPEN = 0; } //Setup SPI void spi1_Initialize(void) { //setup SPI //SSP1STAT = 0x80; // Mode 0(PIC) = Mode 0(Mem), sample at the END //SSP1STAT = 0x00; // Mode 0(PIC) = Mode 0(Mem), sample at the MIDDLE //SSP1STAT = 0xC0; // Mode 1(PIC) = Mode 0(Mem), sample at the END SSP1STAT = 0x40; // Mode 1(PIC) = Mode 0(Mem), sample at the MIDDLE // SSPEN enabled; CKP Idle:Low, Active:High; SSPM FOSC/4_SSPxADD; SSP1CON1 = 0x2A;
SSP1CON2 = 0x00; //SSP1CON3 = 0x00;
// Divider of the clock => 400 kHz SSP1ADD = 0x04; // Fix the SCK at 0, so when nCS is LOW, it will detect the mode 0, p.5 last § TRISBbits.TRISB6 = 0x00; } // Full Duplex SPI Functions uint8_t spi1_exchangeByte(uint8_t b) { // Clear the Write Collision flag, to allow writing SSP1CON1bits.WCOL = 0;
SSP1BUF = b; while(!PIR3bits.SSP1IF); PIR3bits.SSP1IF = 0; return SSP1BUF; } void spi1_exchangeBlock(void *block, size_t blockSize) { uint8_t *data = block; while(blockSize--) { *data = spi1_exchangeByte(*data); data++; } } // Half Duplex SPI Functions void spi1_writeBlock(void *block, size_t blockSize) { uint8_t *data = block; while(blockSize--) { spi1_exchangeByte(*data++); } } void spi1_readBlock(void *block, size_t blockSize) { uint8_t *data = block; while(blockSize--) { *data++ = spi1_exchangeByte(0); } } |
Thank you in advance if you have taken the time to read all the way and help me.
I remain at your disposal for further information.
Have a good day.
Best regards,
Michael
Solved! Go to Solution.
- Labels:
-
ispn:35577:1:0
-
l1:4041:1:0
-
l2:4043:1:0
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Michael,
We found out that, the chip select pin is configured as an input. It should be configured as an output pin in the controller similar to SI and SCK pins. Could you please test after configuring chip select pin as an output?
Thanks and Regards,Sudheesh
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Michael,
Thank you for providing the details about the issue. Could you please attach SPI waveform (SO, SI, SCK and CS# signals) for "read device ID" operation also?
Thanks and Regards,
Sudheesh
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear Sudheesh,
I unfortunately don't have an oscillator on hand....
Best regards,
Michael
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Michael,
I checked SPI mode waveform in datasheet of PIC16LF18446 (http://ww1.microchip.com/downloads/en/DeviceDoc/Microchip-8-bit-PIC-MCU-PIC16(L)F18426_46-Datasheet-... , page 508). Our device changes the data on SO signal along with falling edge of the clock, so that the master can sample it along with the rising edge. So, can you change the bit SMP to 1 in SSP1STAT register and check?
Thanks and Regards,
Sudheesh
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Sudheesh,
I tried what you suggested as SPP1STAT = 0xC0 = 0b 1100 0000 and it doesn't work either.
EDIT : I tried all these modes with the same result.
//setup SPI => MODE 0 and 1 of PIC
SSP1STAT = 0xC0; // Mode 0(PIC) = Mode 0(Mem), sample at the END 1100
// NO SSP1STAT = 0x40; // Mode 0(PIC) = Mode 0(Mem), sample at the MIDDLE 0100
// NO SSP1STAT = 0x80; // Mode 1(PIC) = Mode 0(Mem), sample at the END 1000
// NO SSP1STAT = 0x00; // Mode 1(PIC) = Mode 0(Mem), sample at the MIDDLE 0000
// SSPEN enabled; CKP Idle:Low, Active:High; SSPM FOSC/4_SSPxADD;
SSP1CON1 = 0x2A;
// === OR ===
//setup SPI => MODE 2 and 3 of PIC
// NO SSP1STAT = 0xC0; // Mode 2(PIC) = Mode 1(Mem), sample at the END 1100
// NO SSP1STAT = 0x40; // Mode 2(PIC) = Mode 1(Mem), sample at the MIDDLE 0100
// NO SSP1STAT = 0x80; // Mode 3(PIC) = Mode 1(Mem), sample at the END 1000
// NO SSP1STAT = 0x00; // Mode 3(PIC) = Mode 1(Mem), sample at the MIDDLE 0000
// SSPEN enabled; CKP Idle:High, Active:High; SSPM FOSC/4_SSPxADD;
//SSP1CON1 = 0x3A;
Is there any way to ensure that the memory loads its BUFFER register with the right data? For example, in the case of an RDID, it should load the first byte which is 0x7F.
Are there any particularities in the use of the component? I put nHOLD to Vdd, Vdd to ground through a capacity of 100nF, Vss to GND and nWP to Vdd.
Best regards,
Michael
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Sudheesh,
I'm still stuck. However, I was able to verify that the memory was working by using a USB key with a small software that reads and writes on it.
However, my code still doesn't allow me to write or read in this memory. I kept searching and searching everywhere on the internet but I couldn't get SPI communication to work.
You really have no idea how to help me?
Best regards,
Michael
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Michael,
My sincere apologies for the delay in getting back to you.
I reviewed your program that you provided earlier and found that the function call to make CS# signal LOW before SPI operations are missing before RDID (commented the function call "SS1_bar_SetLow();") command and WRITE command. Please call "SS1_bar_SetLow();" before RDID and WRITE operations.
Thanks and Regards,
Sudheesh
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Michael,
We found out that, the chip select pin is configured as an input. It should be configured as an output pin in the controller similar to SI and SCK pins. Could you please test after configuring chip select pin as an output?
Thanks and Regards,Sudheesh