|
|
View previous topic :: View next topic |
Author |
Message |
L.T.
Joined: 24 Jul 2020 Posts: 62
|
Can't read data with SPI using PIC16f18346 |
Posted: Mon Aug 10, 2020 11:20 pm |
|
|
Hi there,
I'm using PIC16F18346, CCS Compiler and SPI protocol. I sent the data with master to slave. Slave device read and answered it, I saw signals (received and transmitted) on the oscilloscope but my master device ( PIC16F18346 ) can't read received signal. What is the problem? My slave device can read data which is LSB first. You can see my code below.
Code: |
#define SPI_MODE_0 ( SPI_L_TO_H | SPI_XMIT_L_TO_H )
#define SPI_MODE_1 ( SPI_L_TO_H )
#define SPI_MODE_2 ( SPI_H_TO_L )
#define SPI_MODE_3 ( SPI_H_TO_L | SPI_XMIT_L_TO_H )
mPPSLOCK.reg = 0x55;
mPPSLOCK.reg = 0x00;
PPSLOCKbitsPPSLOCKED = 0x00; //unlock PPS
//INPUT
mSSP1DATPPS.reg = 0x0C; //RB4 -> MSSP1: SDI1 ---- Set pin RB4 as data input ----- PGA460_MISO_1 PIN12
mSSP1CLKPPS.reg = 0X0E; //RB6 -> MSSP1: SCK1 ---- Set pin RB6 as clock input ---- PGA460_SCK_1 PIN11;
//OUTPUT
mRB6PPS.reg = 0x18; //RB6 -> MSSP1: SCK1 ---- Set pin RB6 as clock output --- PGA460_SCK_1 PIN11;
mRC7PPS.reg = 0x19; //RC7 -> MSSP1: SDO1 ---- Set pin RC7 as data output ---- PGA460_MOSI_1 PIN9;
mPPSLOCK.reg = 0x55;
mPPSLOCK.reg = 0x00;
PPSLOCKbitsPPSLOCKED = 0x01; //lock PPS
// Pin Settings of PIC16F18346
mTRISA.reg =0b00000000; //RA2=OUTPUT (BUZZER Pin)
mTRISB.reg =0b00110000; //RB4=RB5=INPUT (MISO Pins) RB6=RB7=OUTPUT (SCLK Pins)
mTRISC.reg =0b00000000; //RC0=RC4=RC7=OUTPUT (GV_ACTIVE and MOSI Pins)
mANSELA.reg =0b00000000; //PORTA is completely digital
mANSELB.reg =0b00000000; //PORTB is completely digital
mANSELC.reg =0b00000000; //PORTC is completely digital
mPORTA.reg =0b00000000; //Clear PORTA
mPORTB.reg =0b00000000; //Clear PORTB
mPORTC.reg =0b00000000; //Clear PORTC
setup_spi(SPI_MASTER | SPI_MODE_1 | SPI_CLK_DIV_16);
// MSB --> LSB /////////////////////////////////////////////////
_data = (((_data & 0b11110000)>>4) | ((_data & 0b00001111)<<4));
_data = (((_data & 0b11001100)>>2) | ((_data & 0b00110011)<<2));
_data = (((_data & 0b10101010)>>1) | ((_data & 0b01010101)<<1));
////////////////////////////////////////////////////////////////
spi_write(_data);
uint8 recdat=0;
recdat = spi_read();
return recdat; |
I watched recdat with MPLABX Debugger window and I saw recdat=0 only.
NOTE:
1) I can't use SS pin 'cause my slave device doesn't have SS pin but it has SPI protocol.
2) I checked all connections.
3) I tried another pin for set as MISO. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Aug 11, 2020 1:15 am |
|
|
You're trying to do everything manually instead of using the CCS
#pin_select directive. That's OK, but you didn't read the 16F18346
datasheet on page 161. It shows the instruction sequence that must
be followed to lock/unlock PPS. It sends a 0x55 and a 0xAA and you're
not doing that. 16F18346 Data sheet:
http://ww1.microchip.com/downloads/en/DeviceDoc/40001839E.pdf
EXAMPLE 13-1: PPS LOCK/UNLOCK SEQUENCE
Code: |
bcf INTCON,GIE ; suspend interrupts
BANKSEL PPSLOCK ; set bank
; Required sequence, next 5 instructions:
movlw 0x55
movwf PPSLOCK
movlw 0xAA
movwf PPSLOCK
; Set PPSLOCKED bit (BSF instr.) to disable writes or
; clear PPSLOCKED bit (BCF instr.) to enable writes:
bsf PPSLOCK, PPSLOCKED ; Writes disabled with BSF instr.
bsf INTCON,GIE ; restore interrupts |
You wrote:
Quote: |
spi_write(_data);
uint8 recdat=0;
recdat = spi_read();
return recdat;
|
You didn't read the section in the CCS manual on spi_read().
It says this:
Quote: |
If there is no data to send just do a spi_read(0) to get the clock. |
You have to give it a 0x00 parameter to get the SPI master to generate
the clock bits to do that read. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Tue Aug 11, 2020 1:16 am |
|
|
Tell us what the device is?.
It could be a signalling level problem.
SPI requires the signals to go up to 0.8*Vdd.
However there is an issue with what you type:
Code: |
spi_write(_data);
uint8 recdat=0;
//This will read the byte that was clocked to you when you
//wrote '_data'. Do you actually want to clock a byte back?.
recdat = spi_read();
//If so, you need instead...
recdat = spi_read(0); //this clocks a byte out to read the data
return recdat;
|
I see PCM pointed out the same thing.
However I didn't realise he was trying to do the pin select himself.
He is sending 55, 00, rather then 55 AA... :( |
|
|
L.T.
Joined: 24 Jul 2020 Posts: 62
|
|
Posted: Tue Aug 11, 2020 1:55 am |
|
|
Thanks for all reply.
1) I tried "spi_read(0)" but I can't read.
2) And about the other suggest, should I write the code like follow? Did you say like this?
Code: |
#define SPI_MODE_0 ( SPI_L_TO_H | SPI_XMIT_L_TO_H )
#define SPI_MODE_1 ( SPI_L_TO_H )
#define SPI_MODE_2 ( SPI_H_TO_L )
#define SPI_MODE_3 ( SPI_H_TO_L | SPI_XMIT_L_TO_H )
mPPSLOCK.reg = 0x55;
mPPSLOCK.reg = 0xAA;
PPSLOCKbitsPPSLOCKED = 0x00; //unlock PPS
//INPUT
mSSP1DATPPS.reg = 0x0C; //RB4 -> MSSP1: SDI1 ---- Set pin RB4 as data input ----- PGA460_MISO_1 PIN12
mSSP1CLKPPS.reg = 0X0E; //RB6 -> MSSP1: SCK1 ---- Set pin RB6 as clock input ---- PGA460_SCK_1 PIN11;
//OUTPUT
mRB6PPS.reg = 0x18; //RB6 -> MSSP1: SCK1 ---- Set pin RB6 as clock output --- PGA460_SCK_1 PIN11;
mRC7PPS.reg = 0x19; //RC7 -> MSSP1: SDO1 ---- Set pin RC7 as data output ---- PGA460_MOSI_1 PIN9;
mPPSLOCK.reg = 0x55;
mPPSLOCK.reg = 0xAA;
PPSLOCKbitsPPSLOCKED = 0x01; //lock PPS
// Pin Settings of PIC16F18346
mTRISA.reg =0b00000000; //RA2=OUTPUT (BUZZER Pin)
mTRISB.reg =0b00110000; //RB4=RB5=INPUT (MISO Pins) RB6=RB7=OUTPUT (SCLK Pins)
mTRISC.reg =0b00000000; //RC0=RC4=RC7=OUTPUT (GV_ACTIVE and MOSI Pins)
mANSELA.reg =0b00000000; //PORTA is completely digital
mANSELB.reg =0b00000000; //PORTB is completely digital
mANSELC.reg =0b00000000; //PORTC is completely digital
mPORTA.reg =0b00000000; //Clear PORTA
mPORTB.reg =0b00000000; //Clear PORTB
mPORTC.reg =0b00000000; //Clear PORTC
setup_spi(SPI_MASTER | SPI_MODE_1 | SPI_CLK_DIV_16);
// MSB --> LSB /////////////////////////////////////////////////
_data = (((_data & 0b11110000)>>4) | ((_data & 0b00001111)<<4));
_data = (((_data & 0b11001100)>>2) | ((_data & 0b00110011)<<2));
_data = (((_data & 0b10101010)>>1) | ((_data & 0b01010101)<<1));
////////////////////////////////////////////////////////////////
spi_write(_data);
uint8 recdat=0;
recdat = spi_read(0);
return recdat;
|
I tried this code but the received signal I observed on the oscilloscope has deteriorated.
3) I'm using PGA460PSM-EVM as slave device. These are communicate each other 3.3V level. I applied 3.3V supply voltage to the PIC16F18346 master. When I watched signals on the oscilloscope, I saw that the received and transmitted signals had a level of 3.3V. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Aug 11, 2020 2:38 am |
|
|
Quote: | should I write the code like follow? |
No, you should use CCS and write it using it CCS functions and directives.
Study the manual. |
|
|
L.T.
Joined: 24 Jul 2020 Posts: 62
|
|
Posted: Tue Aug 11, 2020 2:44 am |
|
|
I looked but I didn't find anything about my problem. I have to set manually SPI pins using PPS if I want to use PIC16F18346. When I changed spi_read() function as spi_read(0) you told, received signal is broken. When I changed 55-00 as 55-AA, that didn't change anything. If you can help me, I would be very happy. I'm new to coding, I need your helps. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Tue Aug 11, 2020 2:52 am |
|
|
Look at the 'sticky' at the top of the forum.
Use #PIN_SELECT. |
|
|
L.T.
Joined: 24 Jul 2020 Posts: 62
|
|
Posted: Tue Aug 11, 2020 4:27 am |
|
|
I edited the code like follows.
Code: | #define SPI_MODE_0 ( SPI_L_TO_H | SPI_XMIT_L_TO_H )
#define SPI_MODE_1 ( SPI_L_TO_H )
#define SPI_MODE_2 ( SPI_H_TO_L )
#define SPI_MODE_3 ( SPI_H_TO_L | SPI_XMIT_L_TO_H )
// Pin Settings of PIC16F18346
mTRISA.reg =0b00000000; //RA2=OUTPUT (BUZZER Pin)
mTRISB.reg =0b00110000; //RB4=RB5=INPUT (MISO Pins) RB6=RB7=OUTPUT (SCLK Pins)
mTRISC.reg =0b00000000; //RC0=RC4=RC7=OUTPUT (GV_ACTIVE and MOSI Pins)
mANSELA.reg =0b00000000; //PORTA is completely digital
mANSELB.reg =0b00000000; //PORTB is completely digital
mANSELC.reg =0b00000000; //PORTC is completely digital
mPORTA.reg =0b00000000; //Clear PORTA
mPORTB.reg =0b00000000; //Clear PORTB
mPORTC.reg =0b00000000; //Clear PORTC
#define FoscDef 16000000
#use delay(clock=FoscDef)
#pin_select SDI1=PIN_B4
#pin_select SCK1IN=PIN_B6
#pin_select SCK1OUT=PIN_B6
#pin_select SDO1=PIN_C7
#use spi()
setup_spi(SPI_MASTER | SPI_MODE_1 | SPI_CLK_DIV_16);
// MSB --> LSB /////////////////////////////////////////////////
_data = (((_data & 0b11110000)>>4) | ((_data & 0b00001111)<<4));
_data = (((_data & 0b11001100)>>2) | ((_data & 0b00110011)<<2));
_data = (((_data & 0b10101010)>>1) | ((_data & 0b01010101)<<1));
////////////////////////////////////////////////////////////////
spi_write(_data);
uint8 recdat=0;
recdat = spi_read();
return recdat; |
Nothing has changed. Master transmitted the signal, slave received the answer, master didn't read the received signal. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Tue Aug 11, 2020 7:54 am |
|
|
There's a basic, need-to-know, hardware problem...
We don't KNOW what the 'SPI device' is.
SPI has 4 modes and using the wrong mode will cause no end of problems( kinda works, sorta works,etc.)
As 99.44% of all 'peripheral' devices are '3 volt' today, it's vital you tell us what it is. For instance it's bad to connect a 3 volt 'device' to a PIC with a 5 volt VDD or power supply.
Not only do we need to know the 'device' , also critical , is this the 'chip' or a 'module' . If a 'module', post a link to the manufacture's website/product information.
Some 'modules' will have logic level conversion allowing use at 5 volts, some don't, some will have necessary pullups, some won't,..... |
|
|
L.T.
Joined: 24 Jul 2020 Posts: 62
|
|
Posted: Tue Aug 11, 2020 8:41 am |
|
|
I'm using PGA460PSM-EVM demo board, I tried it with MSP module firstly, it worked. And then, I edited for PIC all codes and everything is okay except SPI reading. You can find all documents this link: https://www.ti.com/tool/PGA460PSM-EVM#technicaldocuments
I used demo code given on this link. I could send my data to slave from master, and module (slave) reacted my data and send correct answer to master. I saw all signals on the oscilloscope, I'm sure that signals true because I analyzed this signal with demo code and MSP before. These are same signals. I cannot understand how it is possible that it cannot read the signal I observed on its SDI pin. I used 3.3V power supply to PIC16F18346, 7.6V power supply to PGA460PSM-EVM. PGA460 communicates 3.3V SPI signals. Is this code I wrote wrong? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Aug 11, 2020 9:57 am |
|
|
Quote: | spi_write(_data);
uint8 recdat=0;
recdat = spi_read();
return recdat; |
To get the slave to transmit data to the master, the
master needs to generate a clock. You do this with
recdata = spi_read(0);
If the signal degrades, as you said, then you are doing something else
wrong. Fix that something else.
--------------
Also, you are showing us code fragments. A lot of what you are doing
doesn't make any sense. But it's hard to judge the full effects of what
you are doing because we're not given a full test program.
For example, you've posted this:
Quote: | #define FoscDef 16000000
#use delay(clock=FoscDef)
#pin_select SDI1=PIN_B4
#pin_select SCK1IN=PIN_B6
#pin_select SCK1OUT=PIN_B6
#pin_select SDO1=PIN_C7
#use spi()
setup_spi(SPI_MASTER | SPI_MODE_1 | SPI_CLK_DIV_16);
|
Is this code placed in main() or maybe not ? We can't tell.
In truth, some of it should be above main() and some inside main(), and
some of it shouldn't be there at all.
Post a test program so we can fully critique it.
Also, how do you know that your EVM board uses SPI mode 1 ?
Where is that stated in the EVM board documentation ?
-----------------
The CCS compiler is a generic C compiler (for C89/C90) with numerous
extensions to handle the PIC microcontrollers.
You're using CCS as a generic C compiler and trying to write your own
extensions. This is not the correct way to use the compiler.
You should be using CCS extensions. CCS has functions to set the TRIS
and CCS has functions to disable the analog ports. Use them ! They are
documented in the CCS manual.
http://www.ccsinfo.com/downloads/ccs_c_manual.pdf
-----------------------
CCS does a lot of things for you. For example, it automatically disables
the analog ports in the startup code. This means you don't have to do it.
The startup code for your PIC is shown below:
Quote: |
.................... void main()
0003: MOVLB 12
0004: CLRF OSCTUNE
0005: CLRF OSCCON3
0006: CLRF OSCEN
0007: MOVLW 03
0008: MOVWF OSCFRQ
0009: MOVLW 60
000A: MOVWF OSCCON1
000B: MOVLB 03
000C: CLRF ANSELA
000D: CLRF ANSELB
000E: CLRF ANSELC |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Tue Aug 11, 2020 3:02 pm |
|
|
OK, I downloaded a PDF from the TI website about the EVM and, sigh, it certainly lacks a lOT of information but one 'little' sentence alarmed me. It seems there's a 3 bit address for this module, so you can have 8 units. Makes me wonder just HOW you send the 'device addess' to it to retrieve data. Also something about the 'test' pin being high or low configures the module for 3 or 5 volt operation.....
Have to wonder why not just use the UART configuration ? |
|
|
L.T.
Joined: 24 Jul 2020 Posts: 62
|
|
Posted: Wed Aug 12, 2020 12:00 am |
|
|
Code: |
#define FoscDef 16000000
#fuses RSTOSC_HFINTRC,LVP,DEBUG
#use delay(clock=FoscDef)
void spi_initialize_pga460(void)
{
#define FoscDef 16000000
#use delay(clock=FoscDef)
#pin_select SDI1=PIN_B4
#pin_select SCK1IN=PIN_B6
#pin_select SCK1OUT=PIN_B6
#pin_select SDO1=PIN_C7
#use spi()
setup_spi(SPI_MASTER | SPI_MODE_1 | SPI_CLK_DIV_16);
}
uint8 usscSPI_transfer(uint8 _data) {
uint8 _regdata=0;
// MSB --> LSB /////////////////////////////////////////////////
_data = (((_data & 0b11110000)>>4) | ((_data & 0b00001111)<<4));
_data = (((_data & 0b11001100)>>2) | ((_data & 0b00110011)<<2));
_data = (((_data & 0b10101010)>>1) | ((_data & 0b01010101)<<1));
////////////////////////////////////////////////////////////////
mSSP1BUF.reg = _data;
while(!SSP1IF); //wait
uint8 flagg = SSP1IF;
mSSP1BUF.reg = 0b11111111;
while(!SSP1IF); //wait
_regdata=mSSP1BUF.reg;
// LSB --> MSB /////////////////////////////////////////////////
_regdata = (((_regdata & 0b11110000)>>4) | ((_regdata & 0b00001111)<<4));
_regdata = (((_regdata & 0b11001100)>>2) | ((_regdata & 0b00110011)<<2));
_regdata = (((_regdata & 0b10101010)>>1) | ((_regdata & 0b01010101)<<1));
////////////////////////////////////////////////////////////////
return _regdata;
}
void setup() { // put your setup code here, to run once
// Pin Settings of PIC16F18346
mTRISA.reg =0b00000000; //RA2=OUTPUT (BUZZER Pin)
mTRISB.reg =0b00110000; //RB4=RB5=INPUT (MISO Pins) RB6=RB7=OUTPUT (SCLK Pins)
mTRISC.reg =0b00000000; //RC0=RC4=RC7=OUTPUT (GV_ACTIVE and MOSI Pins)
mANSELA.reg =0b00000000; //PORTA is completely digital
mANSELB.reg =0b00000000; //PORTB is completely digital
mANSELC.reg =0b00000000; //PORTC is completely digital
mPORTA.reg =0b00000000; //Clear PORTA
mPORTB.reg =0b00000000; //Clear PORTB
mPORTC.reg =0b00000000; //Clear PORTC
spi_initialize_pga460();
}
double pga460_printUltrasonicMeasResult(BYTE umr)
{
int speedSound = 343; // speed of sound in air at room temperature
return pga460_printUltrasonicMeasResultExt(umr, speedSound);
}
double pga460_printUltrasonicMeasResultExt(BYTE umr, int speedSound)
{
double objReturn = 0;
double digitalDelay = 0; // TODO: compensates the burst time calculated as number_of_pulses/frequency.
uint16 objDist = 0;
uint16 objWidth = 0;
uint16 objAmp = 0;
objDist = (ultraMeasResult[1]<<8) + ultraMeasResult[2];
objReturn = (objDist/2*0.000001*speedSound) - digitalDelay;
return objReturn;
}
void pga460_spiMosiIdle(BYTE size)
{
memset(misoBuf, 0x00, sizeof(misoBuf)); // idle-low receive buffer data
for (int i = 0; i<size; i++)
{
misoBuf[i] = usscSPI_transfer(0xFE);
}
return;
}
BOOLEAN pga460_pullUltrasonicMeasResult(BOOLEAN busDemo)
{
memset(ultraMeasResult, 0, sizeof(ultraMeasResult));
pga_bufu5 pgau5;
pgau5.pgab5.s_syncBYTE=syncBYTE;
pgau5.pgab5.s_UMR=UMR;
pgau5.pgab5.s_pga460_calcChecksum=pga460_calcChecksum(UMR);
pga460_spiTransfer(pgau5.pga_bufdizi5, sizeof(pga_bufs5));
// MOSI transmit 0xFF to pull MISO return data
pga460_spiMosiIdle(numObj*4+1);
// copy MISO global array data to local array based on number of objects
for(int n=0; n<(2+(numObj*4)); n++)
{
ultraMeasResult[n+1] = misoBuf[n];
}
return true;
}
void main(){
setup();
for(;;){ // put your main code here, to run repeatedly
distance = pga460_printUltrasonicMeasResult(0+(i*3));
delay_us(commandDelay);
}
}
|
Code is so long and I can't share with you completely. Basically you can see upstairs the code's part. I want to use SPI because I will use 2 PGA module and I need 2 port SPI or UART. I have PIC16F18346 and it has 2 SPI. Therefore I have to use SPI protocol. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Wed Aug 12, 2020 1:52 am |
|
|
One thing screams to me. The 'Test' pin needs to be pulled high when
power is applied, to switch the chip to using 5v I/O. Otherwise if this is
floating it wakes in 3.3v mode. The schematic shows this going to 'TE', and no
connection to this.
So I think the board is in 3.3v mode, |
|
|
L.T.
Joined: 24 Jul 2020 Posts: 62
|
|
Posted: Wed Aug 12, 2020 2:40 am |
|
|
Hi Ttelmah,
I'm not sure I understand you. Can you say more clear, I think my english is not enough. I'm applied 3.3V supply voltage to PIC (master device). It needs to communicate with 3.3V because PGA460 provides it. What did you mean by test pin? What is 'TE'? If you told about PGA460's Test pin, I don't know what to do with this. I am using the module of PGA460 (PGA460PSM-EVM) and test pin is not given to the module output. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|