View previous topic :: View next topic |
Author |
Message |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Wed Apr 08, 2009 3:45 pm |
|
|
As expected, the PIC24FJ128GA106 SPI is working regularly. As with other PIC24, it's recommended to read the datasheet thoroughly and to check, which PCD built-in functions are working correctly and which are apparently faulty. I used PCD V4.084. There may be SPI related changes towards V4.090, but rather unlikely.
I used this setup, with some additional definitions.
Code: | #define SPI_CLK_DIV_2 0x001B
#define SPI_CPHA_0 0x0100
#define SPI_MODE_0 (SPI_L_TO_H | SPI_CPHA_0)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L | SPI_CPHA_0)
#define SPI_MODE_3 (SPI_H_TO_L)
setup_spi(SPI_MASTER | SPI_MODE_3 |SPI_CLK_DIV_1); |
#pin_select preprocessor commands are generally functional, except for the RPI45 input pin that's used for SDI1 in my application. So I had to go back to manual register settings (not shown here).
Code: | #pin_select SDI1=PIN_xx
#pin_select SDO1=PIN_F3
#pin_select SCK1OUT=PIN_D9 |
From the read/write built-in functions, only spi_read(data) is working correctly, and it must not be used without an argument. As in other cases, PCD built-in functions apparently have never been tested at CCS.
Code: | SPI_nCS_LAT = 0;
spi_read(0xAB);
spi_read(0);
spi_read(0);
spi_read(0);
bID=spi_read(0);
SPI_nCS_LAT = 1; |
The above code reads the ID byte from a serial flash memory, proving that the interface is operating correctly.
I also tried #use spi, but an error message informed me, that it isn't supporting hardware SPI. |
|
|
geokonst
Joined: 04 Apr 2009 Posts: 27
|
|
Posted: Wed Apr 08, 2009 8:57 pm |
|
|
Dear Fvm,
Thank you for your reply.
Could you please clarify for me the following;
What exactly SPI_CPHA_0 is doing?
How did you find out that RPI45 was not working with pin_select? Did you get an error message? could this be causing my problem?
Finally why are you using four spi_reads? Do you need to send 3 bytes before the memory chip responds or is it some other reason?
Thanks for you help. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Thu Apr 09, 2009 12:42 am |
|
|
Quote: | What exactly SPI_CPHA_0 is doing | It's used to set the clock phase (CPHA in the original Motorola SPI terminology). Without setting this bit, PIC24 SPI operation defaults to mode 1 and mode 3. With PCH, this option could be set by SPI_XMIT_L_TO_H. As said, you have to read the PIC24 datasheet. (And should know, which SPI modes are supported by the connected peripheral).
Code: | #pin_select SDI1=PIN_F6 | results in an "Invalid Pin" error. (PIN_F6 is RPI45)
Quote: | Finally why are you using four spi_reads? | Sending 3 dummy bytes is simply required by the serial flash. Nothing specific to PIC24. |
|
|
geokonst
Joined: 04 Apr 2009 Posts: 27
|
|
Posted: Thu Apr 09, 2009 1:03 pm |
|
|
Ok I think I've done whatever there is to do to make this work (at least for a newbie).
I just don't get it.
This code: Code: | #include "D:\...hardware.h"
#PIN_SELECT SDI1=PIN_G8
#PIN_SELECT SDO1=PIN_G7
#PIN_SELECT SCK1OUT=PIN_G6
#PIN_SELECT U2TX=PIN_F5
#PIN_SELECT U2RTS=PIN_F4
#use rs232(UART2,baud=19200,parity=N,bits=8)
#define SPI_CLK_DIV_2 0x001B
#define SPI_MODE_3 (SPI_H_TO_L)
#define cs PIN_B2
#define id 0x8f
#define getx 0xa9
#define gety 0xab
#define getz 0xad
int dataout;
main(){
setup_spi(SPI_MASTER | SPI_MODE_3 |SPI_CLK_DIV_1);
output_low(PIN_B15);
//who_am_i
output_low(cs);
spi_read(id);
dataout=spi_read(0);
putc(dataout);
output_high(cs);
delay_ms(500);
//cfg
output_low(cs);
spi_read(0x20);
spi_read(0xC7); //11000011
output_high(cs);
while (1){
putc (0x80);
output_low(cs);
spi_read(getx);
dataout=spi_read(0);
putc(dataout);
output_high(cs);
output_low(cs);
spi_read (gety);
dataout=spi_read(0);
putc(dataout);
output_high(cs);
output_low(cs);
spi_read (getz);
dataout=spi_read(0);
putc(dataout);
output_high(cs);
}
} |
Does not work (sends 80 and 3 zeroes to the serial port)
The same sequence with my software spi:
Code: | #include "C:\...uclboard.h"
#PIN_SELECT U2TX=PIN_F5
#PIN_SELECT U2RTS=PIN_F4
#use rs232(UART2,baud=19200,parity=N,bits=8)
#define in PIN_G8
#define out PIN_G7
#define clk PIN_G6
#define cs PIN_B2
#define id 0x8f
#define getx 0xa9
#define gety 0xab
#define getz 0xad
int recVal = 0x00;
int i;
void spisend(sendVal)
{
for (i=7;i>=0;i--){
output_bit(out,BIT_TEST(sendVal,i));
output_low(clk);
output_high(clk);
}
}
void spiread()
{
for (i=7;i>=0;i--){
output_low(clk);
if (input(in)){
BIT_SET(recVal,i);
}
output_high(clk);
}
putc(recVal);
recVal=0x00;
}
void main()
{
output_low(PIN_B15);
output_high(clk);
//who_am_i
output_low(cs);
spisend(id);
//spiread();
output_high(cs);
delay_ms(500);
//cfg
output_low(cs);
spisend(0x20);
spisend(0xC7); //11000011
output_high(cs);
while (1){
putc (0x80);
output_low(cs);
spisend(getx);
spiread();
output_high(cs);
output_low(cs);
spisend(gety);
spiread();
output_high(cs);
output_low(cs);
spisend(getz);
spiread();
output_high(cs);
}
}
|
Works perfectly!
both files have the same .h
Code: | #include <24FJ256GB106.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOJTAG //JTAG disabled
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOWRT //Program memory not write protected
#FUSES NODEBUG //No Debug mode for ICD
#FUSES ICS3 //ICD communication channel 3
#FUSES WINDIS //Watch Dog Timer in non-Window mode
#FUSES WPRES128 //Watch Dog Timer PreScalar 1:128
#FUSES WPOSTS16 //Watch Dog Timer PostScalar 1:32768
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES FRC_PS //Fast RC Oscillator with Post Scaler
#FUSES NOCKSFSM //Clock Switching is disabled, fail Safe clock monitor is disabled
#FUSES NOOSCIO //OSC2 is general purpose output
#FUSES NOPR //Pimary oscillaotr disabled
#FUSES IOL1WAY //Allows only one reconfiguration of peripheral pins
#FUSES WPEND_LOW
#FUSES NOWPCFG
#FUSES NOWPDIS
#FUSES WPFP0
#FUSES PLL12 //Divide By 12(48MHz oscillator input)
#FUSES RESERVED //Used to set the reserved FUSE bits
#use delay(internal=8M)
|
...and were uploaded to the very same hardware one after the other.
Unfortunately I blew up my Explorer 16 board and can't use the scope any more, but last time I tried I got a good response from the accelerometer (LIS302DL) on h/w spi but the pic wouldn't read it. I can still use the serial though.
If anyone has an idea PLEASE PLEASE post it. This can't be so hard! |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Thu Apr 09, 2009 2:44 pm |
|
|
I don't see anything wrong with your hardware SPI usage. Also the #pin_select commands seem to generate correct code. |
|
|
geokonst
Joined: 04 Apr 2009 Posts: 27
|
|
Posted: Thu Apr 09, 2009 3:48 pm |
|
|
What's going wrong then? It's driving me mad. Why doesn't it read a perfectly sent response? I really don't want to switch back to C30! I hate c30! |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Thu Apr 09, 2009 4:15 pm |
|
|
It's not necessarily a PCD issue. Although hardware SPI should be able to communicate with the ST acceloremeter, there may be a problem with your hardware and the faster HW operation. I would try to trace it at the hardware level. You also could replace the device with a SDO/SDI loopback to verify basic send/receive operation. |
|
|
geokonst
Joined: 04 Apr 2009 Posts: 27
|
|
Posted: Thu Apr 09, 2009 4:35 pm |
|
|
But, you see the accelerometer is responding, so if it's a hardware issue it must be PIC's
The loopback is a very good idea! |
|
|
geokonst
Joined: 04 Apr 2009 Posts: 27
|
|
Posted: Thu Apr 09, 2009 6:41 pm |
|
|
The loopback test failed as well. I still get zeros. And I've tried different pins too. :(
FvM could the fact that I'm using the internal osc have anything to do with it? Doesn't sound likely but I'm running out of ideas. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Fri Apr 10, 2009 2:59 am |
|
|
As previously reported, hardware SPI is basically working with PIC24F chips, at least using the read_spi() instruction. I tested with V4.084 and most recent V4.090. Of course, I had to check with my hardware, that is using different pins, so it must not necessarily work with your configuration. I also can't see, if there's something in your hardware.h include file that disturbs SPI operation. Generally I would proceed like this:
- check the code operation at the assembly/register level with MPLAB debugger (requires e.g. ICD2 or PICkit ICSP adapter).
- check the hardware operation with an oscilloscope or other hardware debug tools
I don't expect problems related to internal oscillator. |
|
|
Ken Johnson
Joined: 23 Mar 2006 Posts: 197 Location: Lewisburg, WV
|
|
Posted: Fri Apr 10, 2009 7:05 am |
|
|
I'm using SPI on 24H for 2 different devices (ADC and FRAM) at 2 different clock speeds, using (sorry) Microchip's C30. Here are some code snippets:
Code: |
SPI2STAT = 0; // Disable the SPI2 module for setup;
SPI2CON1bits.CKP = 0; // Clock idles lo;
SPI2CON1bits.CKE = 1; // Read data on rising edge of SCK;
SPI2CON1bits.MSTEN = 1; // PIC is the master;
SPI2CON1bits.PPRE = 2;
|
and
Code: |
void SaveFRAM (ushort offset, const void *pRAM, ushort nBytes)
// Writes nBytes from pRAM into STORAGE at offset:
{
const dbyte *p;
ushort nWords;
nWords = nBytes / 2; // 16-bit transfers;
p = (dbyte*) pRAM; // Pointer to 16-bit items;
TaskBlock (ProcessTask); // Shares the SPI Port;
SPI2CON1bits.MODE16 = 0; // 8-bit transfers on SPI2;
SPI2CON1bits.SPRE = 7; // 10MHz (max SCLK);
SPI2STATbits.SPIEN = 1; // Enable the SPI module;
SelectFRAM (0); // Chip Select;
SPI2BUF = WREN; // Write the command and wait:
while ( !SPI2STATbits.SPIRBF );
SPI2BUF; // Read buffer to clear SPIRBF;
SelectFRAM (1); // Toggle Chip Select;
SelectFRAM (0); // Write the next command:
SPI2BUF = WRITE;
while ( !SPI2STATbits.SPIRBF );
SPI2BUF; // Read buffer to clear SPIRBF;
SPI2STAT = 0; // Disable the SPI, and change mode:
SPI2CON1bits.MODE16 = 1; // Now do 16-bit transfers;
SPI2STATbits.SPIEN = 1; // Enable the SPI module;
SPI2BUF = offset; // Write the address;
while ( !SPI2STATbits.SPIRBF );
SPI2BUF; // Read buffer to clear SPIRBF;
while ( nWords-- ) { // Now write all the data:
SPI2BUF = *p++;
while ( !SPI2STATbits.SPIRBF );
SPI2BUF;
}
SelectFRAM (1);
SPI2STAT = 0; // Disable PIC SPI, and clear the read overrun flag;
TaskUnBlock (ProcessTask);
}
|
Maybe comparing this with the CCS generated asm code will show something?
Best of luck!
Ken |
|
|
Guest
|
|
Posted: Sat Apr 11, 2009 9:11 am |
|
|
geokonst-
I've made some progress over the last day or so, however I've done so using software SPI similar to what you've posted. Still nothing with the hardware (and still waiting for a response from Microchip). I was attempting to use port D on the PIC, of which one of the pins I was using apparently didn't work. However I tried port G like you were using and still didn't get a response. I'll keep you posted if I hear back from Microchip or get the hardware to work. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sat Apr 11, 2009 11:15 am |
|
|
I would be suprized, if there's a hardware problem with certain pins, but can be, of course. Anyway, it's interesting to know, which part of the SPI function is apparently failing: SCK, SDO or SDI/receive. |
|
|
geokonst
Joined: 04 Apr 2009 Posts: 27
|
|
Posted: Sat Apr 11, 2009 5:32 pm |
|
|
I have too tried pins D1, D2, D3, G8, G7 with no luck (no compiler errors). I don't believe its a pin problem as pps works fine with the serial port. Also I've tried manually setting I/O direction.
The customer support sent me the following code which they say compiles:
Code: | #include <24fj256ga110.h>
#use delay(clock=40mhz)
#PIN_SELECT SDI1=PIN_G8
#PIN_SELECT SDO1=PIN_G7
#PIN_SELECT SCK1OUT=PIN_G6
#PIN_SELECT SS1OUT=PIN_B1
#PIN_SELECT U2TX=PIN_F5
#PIN_SELECT U2RTS=PIN_F4
#use rs232(UART1,baud=19200,parity=N,bits=8)
#use spi(SPI1, BITS=16, MODE=3)
int dataout;
void main(){
while (1){
output_low (PIN_B2);
dataout=SPI_XFER(0x8f);
output_a(dataout);
delay_us(50);
output_high (PIN_B2);
delay_ms(3);
}
} |
It doesn't compile for me and the problem is the option "SPI1" in use spi. I have no idea why. Could you please try it and let me know if it compiles on your machine?
I have also tried the registers approach:
Code: | #include "D:\...24FJ256GB106_registers.h"
#PIN_SELECT SDI1=PIN_D1
#PIN_SELECT SDO1=PIN_D3
#PIN_SELECT SCK1OUT=PIN_G6
#PIN_SELECT U2TX=PIN_F5
#PIN_SELECT U2RTS=PIN_F4
#use rs232(UART2,baud=19200,parity=N,bits=8)
#define SPI_MASTER 0x0120 // select 8-bit master mode, CKE=1, CKP=0
#define SPI_ENABLE 0x8000 // enable SPI port, clear status
#define cs PIN_B2
int i;
int writeSPI2( int data)
{
SPI2BUF = data;
delay_ms(500);
return SPI2BUF; // read the received value
}
main()
{
output_high (cs);
SPI2CON1 = SPI_MASTER; // select mode
SPI2STAT = SPI_ENABLE; // enable the peripheral
while (1){
set_tris_d(0xfc);
output_low(cs);
writeSPI2( 0x8F); // send a READ STATUS COMMAND
i = writeSPI2( 0); // send dummy, read data
putc(i);
delay_ms(10);
output_high(cs);
delay_ms(10);
}
} | [/quote]
But I am really inexperienced so I probably have done something wrong.
So what is failing for me is reading the response (or putting the value in a variable). While I had access to an oscilloscope I could see that the communication was perfect. And I have also tried sorting sdi + sdo and still nothing. So SDI seems to be the problem.
Unfortunately I need hardware spi, so if you have any ideas please post them here. Thanks |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sat Apr 11, 2009 6:08 pm |
|
|
I didn't try #use spi with V4.090. As said, it didn't work with V4.084, at least for PIC24FJ128GA106 (and similar GA10x and GB10x chips). As a possible problem, CCS seems not to test built-in functions with the full choice of chips, so a lot of bugs related to chip specific features, register mappings etc. isn't detected.
I don't understand your "register approach", that uses #pin_select for SPI1 but accesses SPI2 registers. This can't work. |
|
|
|