Has any one gotten framed SPI to work on PIC24?
Has any one gotten framed SPI to work on PIC24?
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.
-
- Posts: 619
- Joined: 05 Jul 2008 06:05
- Location: Thailand
This works:
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...
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
}
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...
-
- Posts: 619
- Joined: 05 Jul 2008 06:05
- Location: Thailand
-
- Posts: 183
- Joined: 06 Mar 2008 17:35
- Location: St. George, UT
- Contact:
The "down annd dirty" way
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):
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 ;)
* 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;
}
}
Last edited by steve42lawson on 20 Feb 2023 23:48, edited 1 time in total.
-
- Posts: 619
- Joined: 05 Jul 2008 06:05
- Location: Thailand