Has any one gotten framed SPI to work on PIC24?

General discussion on mikroC for dsPIC30/33 and PIC24.
Post Reply
Author
Message
JIH
Posts: 2
Joined: 07 Oct 2008 22:30

Has any one gotten framed SPI to work on PIC24?

#1 Post by JIH » 07 Oct 2008 22:53

I have gotten my PIC24FJ96A008 to work fine for non-framed SPI. I have tried to enable the frame mode by setting the SPI1CON2 register to 0x8000, I have also tried changing the frame polarity by setting the register to 0xA000. The PIC24 continues to run in non-framed mode, the clock is not free running and I don't get a frame bit on -SS1. I have also tried to run SPI2 with the same results. I have read the errata for the PIC24 so I am running a slow clock.

Sobrietytest
Posts: 619
Joined: 05 Jul 2008 06:05
Location: Thailand

#2 Post by Sobrietytest » 08 Oct 2008 01:30

This works:

Code: Select all

#include <Spi_Const.h>

unsigned Data = 0;
unsigned buffer;
char ostring[7];
const char CS_PIN = 9;
short x;
char second[4], minute[4], hour[4];

unsigned char sec, min1, hr, day, mn, year;
char *txt, tnum[4];

void Get_Angle() {

        PORTG.CS_PIN = 0;               //Send 16-bit Reg address
        Spi2_Write(0x0D00);
        PORTG.CS_PIN = 1;
        Delay_us(30);

        PORTG.CS_PIN = 0;               //Read 16-bit data
        Data = Spi2_Read(buffer);
        PORTG.CS_PIN = 1;
        Delay_us(30);
        Data = Data & (0x3FFF);         //Strip off ND & EA flags(2 MSB's)
        Data = Data/40;
        IntToStr(Data, ostring);        //convert Data to string

}

void Usart_Write_Str( const char *ostring ){  //Send Data string to Uart

     while( *ostring ) Uart2_Write_Char( *ostring++ );
     
}

void Init_main() {
   ADPCFG = 0xFFFF;                        // Set AN pins as digital
   TRISG.CS_PIN = 0;                       // Set RG9 to output
   PORTG.CS_PIN = 1;                       // Set CS high
   //Fire up SPI channel 2
   Spi2_Init_Advanced(_SPI_MASTER, _SPI_16_BIT, _SPI_PRESCALE_SEC_6, _SPI_PRESCALE_PRI_4, _SPI_SS_DISABLE, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_HIGH, _SPI_ACTIVE_2_IDLE);

   Uart2_Init(115200);              //Fire up Uart channel 2 @115200baud
   Delay_ms(100);
   Uart2_Write_Char('S');           //Check Uart comms

   I2C1_Init(100000);               //Fire up I2C channel 1

}
These are the two relevant procedures; Init_main sets up the SPI channel etc, Get_angle sends a 16-bit register address and then reads 16-bit data from it, the 2 MSB's (flags) are stripped off and /40 converts the value to degrees. That value is converted to a string and sent over the Uart.

This runs on a 24FJ96GA010 @ 10MHz with a 4x PLL - when you set up your project you have to be very particular how you set the values in the config word because the defaults don't work, also frequency and timing are very important for both SPI and Uart comms to work - take note of the prescaler values in SPI_Init_ and the small delays in the SPI comm sequence.

I have to say that if I hadn't used a scope I'd still be trying to get it working now! Note that SS is not used when the PIC is in Master mode, I'm force framing by using RG9 as the Chip Select (active low). You will have to read your target device's datasheet to get the rest of Spi_Init_Advanced to work properly.

There's other code within the program that reads an RTC but all the Main does is loop round each procedure.

Hope this helps...

Sobrietytest
Posts: 619
Joined: 05 Jul 2008 06:05
Location: Thailand

#3 Post by Sobrietytest » 08 Oct 2008 01:36

I forgot to mention that your Project Setup frequency must be 40MHz (10MHz with x4 PLL).

steve42lawson
Posts: 183
Joined: 06 Mar 2008 17:35
Location: St. George, UT
Contact:

The "down annd dirty" way

#4 Post by steve42lawson » 12 Nov 2008 18:57

I needed more speed than I was able to get out of the canned SPI functions (Spi1_Init_Advanced, Spi1_Write) so I consulted the Microchip documentation:

* http://www.microchip.com/wwwproducts/De ... e=en026379
* http://ww1.microchip.com/downloads/en/D ... 39699b.pdf

And came up with the following (this is for driving an AD5611 DAC from a PIC24FJ32GA002 to produce a "saw tooth" or ramp waveform):

Code: Select all

int ramp = 0;
void main() {
	// Init SPI1 module
	SPI1STATbits.SPISIDL   = 0;     // Stop in Idle Mode  [0 = Disable during idle]
	SPI1CON1bits.DISSCK    = 0;     // Disable SCK1 clock (master mode only)  [0 = enabled]
	SPI1CON1bits.DISSDO    = 0;     // Disable SDOx Data Out  [0 = enabled]
	SPI1CON1bits.MODE16    = 1;     // 8/16 bit select [1 = 16 bits]
	SPI1CON1bits.CKE       = 1;     // Clock Edge Select 1 = SDO changes on idle to active clock xition]
	SPI1CON1bits.CKP       = 1;     // Clock Polarity [1 = High on idle]
	SPI1CON1bits.SSEN      = 1;     // Slave Select [0 = ~SS1 not used]
	SPI1CON1bits.MSTEN     = 1;     // Master Mode  [1 = Enable]
	SPI1CON1bits.SPRE      = 0x7;   // Secondary Prescale  [111 = 1:1 ... 000 = 8:1]
	SPI1CON1bits.PPRE0     = 1;     // Primary Prescale  [11 = 1:1, 10 = 4:1, 01 = 16:1, 00 = 64:1]
	SPI1CON1bits.PPRE1     = 1;
	SPI1CON2bits.FRMEN     = 1;     // Frame Enable  [1 = Enable Framed ~SS1 Support]
	SPI1CON2bits.SPIFSD    = 0;     // Frame Sync Pulse Direction  [0 = Output (Master)]
	SPI1CON2bits.SPIFPOL   = 1;     // Frame Sync Pulse Polarity  [0 = Acive Low]
	SPI1CON2bits.SPIFE     = 0;     // Frame Sync Pulse Edge Select  [0 = Precedes first clk pulse]
	SPI1CON2bits.SPIBEN    = 0;     // Enhanced Buffer  [0 = disabled (standard mode)]
	
	// Map the SPI module to some pins (change the pin assignments as needed)
	RPOUTR5bits.RP11R0 = 1;       // Set FSYNC1 (9) to RP11
	RPOUTR5bits.RP11R1 = 0;
	RPOUTR5bits.RP11R2 = 0;
	RPOUTR5bits.RP11R3 = 1;
	RPOUTR5bits.RP11R4 = 0;    
	RPOUTR6bits.RP13R0 = 0;       // Set SCK1OUT (8) to RP13
	RPOUTR6bits.RP13R1 = 0;
	RPOUTR6bits.RP13R2 = 0;
	RPOUTR6bits.RP13R3 = 1;
	RPOUTR6bits.RP13R4 = 0;
	RPOUTR6bits.RP12R0 = 1;       // Set SDO1 (7) to RP12
	RPOUTR6bits.RP12R1 = 1;
	RPOUTR6bits.RP12R2 = 1;
	RPOUTR6bits.RP12R3 = 0;
	RPOUTR6bits.RP12R4 = 0;
	
	// Enable the SPI module
	SPI1STATbits.SPIEN     = 1;     // SPI Enable  [1 = Enable]

	//Generate the waveform
	while (1)
	{
		// Wait for the Tx buffer to clear
        	if (SPI1STATbits.SPITBF == 0)
       		{
        		// Write the next byte to the SPI buffer (the SPI module will automatically
        		// transfer it to the SPI1TXB (transmit buffer)
            		SPI1BUF = ramp;
        	}
        	// The least sig 4 bits of the AD5611 are not used, but 16 bits are shifted during each
        	// frame, so by adding 16 I'm effectively shifting by 4.  This can also be done like this
        	//   ++ramp; SPI1BUF = ramp << 4;  if (ramp > 1023) ramp = 0;
        	ramp += 16;
        	if (ramp > 16383) ramp = 16;
	}  
}    

Running this with the FRC_PLL (i.e. clock speed 8Mhz * 4) produces a 183 Hz ramp wave (10bit resolution). I was only able to get about 20 to 30 Hz using the canned functions using the technique shared by Sobrietytest (BTW thank you -- you helped me get this thing running ;)
Last edited by steve42lawson on 20 Feb 2023 23:48, edited 1 time in total.

Sobrietytest
Posts: 619
Joined: 05 Jul 2008 06:05
Location: Thailand

#5 Post by Sobrietytest » 14 Nov 2008 01:35

Thanks for that Steve, nice bit of code. It serves as a neat reminder that the 'canned' library functions should be seen as nothing more than examples - especially in frequency critical applications - and that there's no substitute for understanding how the chips actually work.

Post Reply

Return to “mikroC for dsPIC30/33 and PIC24 General”