News:

Let's find out together what makes a PIC Tick!

Main Menu

SPI clock frequency in Positron 16

Started by Wimax, Oct 09, 2021, 02:16 PM

Previous topic - Next topic

Wimax

Hello everybody!

I would like to use a dsPIC33FJ12GP202 to acquire data from the internal ADC (say up to 100 kbps) and storing it on an external SRAM (23LC1024) using the SPI interface. The SRAM is quite fast, but what is the clock frequency used in the Shout - Shin commands, is there any way to change or control it ?

 :o

Giuseppe

From the proton16 manual :

Shin - Shout Declare.
Declare Shift_DelayUs 0 - 65535 microseconds (us)
Extend the active state of the shift clock.
The clock used by Shin and Shout runs at approximately 45KHz dependent on the oscillator
frequency. The active state is held for a minimum of 2 microseconds, again depending on the
oscillator. By placing this declare in the program, the active state of the clock is extended by an
additional number of microseconds up to 65535 (65.535 milliseconds) to slow down the clock
rate.


Wimax


John Lawton

It might be faster to bit-bash the SPI, not difficult to do.

John

Wimax

Quote from: John Lawton on Oct 11, 2021, 10:37 AMIt might be faster to bit-bash the SPI, not difficult to do.

John

John, do you refer to SPIxCON1<1:0> and SPIxCON1<4:2> control register ?

Stephen Moss

Quote from: John Lawton on Oct 11, 2021, 10:37 AMIt might be faster to bit-bash the SPI, not difficult to do.

John
I think the Shin and Shout commands are bit bashed as you specify the Port pins used for the Clk and Data.

If not using the MSSP module or the pins it requires it should be relatively easy to set up the MSSP module. Once set up, usually it is just a case of writing data to the SSPBUF to start a transmit and then using an interrupt or polling the Buffer Full (BF bit) to know once transmission/reception has completed and reading the incoming data from the SSPBUF to an applicable variable.
Although you might have to use the bitwise reverse command on either the incoming data, outgoing data or both depending on if the SPI device is MSB first or LSB first, as I recall the PIC I used sent out data in the SSPBUF MSB first so I had to reverse the data before sending it to the SSPBUF so that the SPI device received it LSB first. Equally, I also had to reverse the received data from the SSPBUFF as although sent LSB first the SSPBUF is essentially a ring buffer so the sent LSB ends up as the SSPBUF MSB.

John Lawton

Quote from: Wimax on Oct 12, 2021, 08:23 AMJohn, do you refer to SPIxCON1<1:0> and SPIxCON1<4:2> control register ?
Actually I wasn't but this looks the right register to control the SPI bus speed if using the SPI hardware peripheral.
By bit-bashing I meant to generate the SPI signals from scratch by generating the clock and data outputs as below if the SPI hardware isn't fast enough.

Something like:
Set Data_Line ' (if sending a 1)
Set Clk_Line
@nop
Clear Clk_Line
Clear Data_Line
@nop
etc

Would clock one bit of data.

Steven is right that the Shin and Shout commands also generate the SPI waveforms in software, but I think more slowly. If you can get it set up right, using the SPI hardware is usually the easiest/best option.

top204

#7
The problem with the hardware SPI and I2C peripherals, is that they are constantly changed. So the code for one device will not work with another device, of the same family! The PIC24 devices are a little better at keeping the same mechanisms, but the newer types and the newer dsPIC33 devices are getting to the "all different" stage as well. :-(

Whenever possible, I use a software based SPI or I2C routine, so it can be transfered and used on "any" device. The only time I look at hardware SPI is if it is operating within an interrupt and it needs to be very fast and slim, or is operating as a slave unit. However, some of the earlier 18FxxK devices failed when the SPI peripheral was placed at its maximum speed, and this can be seen on an analyser with some of the clock pulses missing. :-( It took me a while to figure out why the external peripherals were failing sometimes, until I placed the logic analyser on the CLK pin of the microcontroller and saw what was happening!

Wimax

I am using dsPIC33FJ12GP202 with an external clock at 7.37 MHz and yesterday I tried some tests using "Shin - Shout Declare". I was able to get a stable transfer rate close to about 90 Kb/s. If I keep the hardware SPI prescalers unchanged and activate the internal PLL to change FCY (e.g. X2) should I be able to increase the SPI clock ?  A factor of 2 would be more than satisfactory  :o

John Lawton

Referring to the datasheet DS70264E page 97/98, the PLL can be fed by the 'Primary Oscillator', using pins OSC1 & 2 or the 'Secondary Oscillator'. I'm not sure where your external 7.37MHz oscillator fits in although the data sheet refers to an internal 7.37MHz oscillator, in which case the PLL could be used.

John

Stephen Moss

Quote from: Wimax on Oct 12, 2021, 10:21 AMI am using dsPIC33FJ12GP202 with an external clock at 7.37 MHz and yesterday I tried some tests using "Shin - Shout Declare". I was able to get a stable transfer rate close to about 90 Kb/s. If I keep the hardware SPI prescalers unchanged and activate the internal PLL to change FCY (e.g. X2) should I be able to increase the SPI clock ?  A factor of 2 would be more than satisfactory  :o
As John indicated, read the data sheet carefully. There is usually more to using the PLL than just selecting that option in the configuration fuses as generally there are various pre and post scalers (Dividers) that need to be correctly set to both meet any primary input frequency range of the PLL and to achieve the desired clock frequency.

Remember that some of the built in commands that are time dependant, i.e. DelayMS/DelayUs and a few others will only produce the correct results if the declared Xtal frequency is correct. When using a PLL that will not be the frequency of the physical Xtal or internal Oscillator used as the primary input to the PLL but that of Frequency of PLL output, i.e. if the physical frequency is 4MHz but the output of the PLL after all the pre and post scalling is 100MHz then Xtal = 100.


Wimax

Yes John, I have a 7.3728 MHz Xtal between OSC1 & OSC2 pins, the data-sheet of the device confirms that "The primary oscillator and internal FRC oscillator can optionally use an on-chip PLL to obtain higher speeds of operation". I think I will have to learn how to correctly configure the device's PLL and try again.

Wimax

Quote from: Stephen Moss on Oct 12, 2021, 12:22 PMAs John indicated, read the data sheet carefully. There is usually more to using the PLL than just selecting that option in the configuration fuses as generally there are various pre and post scalers (Dividers) that need to be correctly set to both meet any primary input frequency range of the PLL and to achieve the desired clock frequency.

Remember that some of the built in commands that are time dependant, i.e. DelayMS/DelayUs and a few others will only produce the correct results if the declared Xtal frequency is correct. When using a PLL that will not be the frequency of the physical Xtal or internal Oscillator used as the primary input to the PLL but that of Frequency of PLL output, i.e. if the physical frequency is 4MHz but the output of the PLL after all the pre and post scalling is 100MHz then Xtal = 100.



Yes, absolutely !

Wimax

Yesterday evening I made some tests by configuring the internal registers of the dsPIC33 and setting the internal PLL to make the MCU work @ 3 different frequencies (one for each test of course) to verify the increase in performance.
Starting from the external oscillator at 7.3728 MHz I used the following triplets: (43,2,8) ; (43,2,4); (43,2,2) to obtain respectively a Fosc of 19.81 MHz, 39.62 MHz, 79.25 MHz and the consequent FCY=FOSC/2.
The performance jump was there, although to a lesser extent than theoretical (I need to check the numbers again). Running the little monster at full speed, I was able to sequentially write 1 MB to the SRAM (mounted on a breadboard by the way) in just under 15 seconds (theoretically at just over 500 Kb/s).
Maybe we can do even better... ???

tumbleweed

Quotetheoretically at just over 500 Kb/s
It's unclear to me if you're using software bit-banging (Shin/Shout) or the SPI hardware.

If you use the SPI peripheral you can easily get several Mb/s

Wimax


top204

#16
The code below is untested, but it shows the principle of creating fast, software based, SPI procedures. It has the benefit of being able to operate on any PIC24 or dsPIC33 device. As far as I can tell, the 33FJ12GP202 should respond the same as the other dsPIC33F devices, so the PLL_Setup meta-macro should work with the particular values in it.

To speed the SPI interfaces up, reduce the value of cSPI_Delay, and to slow them down, increase the value of cSPI_Delay. The DelayCs command allows extremely small delays based upon the instruction cycle times of the microcontroller. Also, using the Carry flag as the bit to transfer, makes the write procedure extremely efficient.

The mode of the SPI interface is also extremely easy to change. It just means toggling the SCK pin at different times, and using a Left or Right shift, and the correct bit to transmit from or receive into. :-)

The internal oscillator of the PIC24 and dsPIC33 devices is very accurate and efficient, so unless the unit is being placed in extreme temperatures, the internal oscillator is a good choice, and very flexible.

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Show the principles of software SPI procedures written for the Positron16 BASIC compiler
'
    Device = 33FJ12GP202                        ' Tell the compiler what device it will be compiling for
    Declare Xtal = 79.23                        ' Tell the compiler the speed that the microcontroller is operating at
'
' Create the pins used for the SPI interface
'
$define SPI_SCK_Pin  PORTB.0                    ' Connects to the slave peripheral's SCK line
$define SPI_MOSI_Pin PORTB.1                    ' Connects to the slave peripheral's MOSI (Master Out Slave In) line
$define SPI_MISO_Pin PORTB.2                    ' Connects to the slave peripheral's MISO (Master In Slave Out) line
$define SPI_CS_Pin   PORTB.3                    ' Connects to the slave peripheral's CS line

$define cSPI_Delay 10                           ' The amount of instruction cycles used for the delay in the SPI procedures
'
' Create some variables for the example
'
    Dim ByteOut As Byte
    Dim ByteIn As Byte

'-----------------------------------------------------------------------------
$define SPI_Start() PinClear SPI_CS_Pin         ' Pull the CS line low to start the SPI coms
$define SPI_Finish() PinSet SPI_CS_Pin          ' Set the CS line high to finish the SPI coms

'-----------------------------------------------------------------------------
' The main program starts here
'
Main:
    PLL_Setup(43, 2, 2, $0300)                  ' Configure the internal oscillator to operate the device at 79.23MHz before we do anything else

    SPI_Setup()                                 ' Setup the pins for the SPI interface
'
' Create a loop to show the write and read procedures syntax and operation
'
    For ByteOut = 0 To 10
        SPI_Start()                             ' Start the SPI interface
        SPI_Mode0_Write8(ByteOut)               ' Write to the SPI interface
        SPI_Finish()                            ' Stop the SPI interface

        SPI_Start()                             ' Start the SPI interface
        ByteIn = SPI_Mode0_Read8()              ' Read from the SPI interface
        SPI_Finish()                            ' Stop the SPI interface
    Next

'-----------------------------------------------------------------------------
' Write an 8-bit value using the SPI mode 0 protocol (MSB first)
' Input     : pValue holds the 8-bit value to send
' Output    : None
' Notes     : SCK is idle-low, and bits are latched on SCK rising
'
Proc SPI_Mode0_Write8(pValue As Byte)
    Dim bLoop As Byte

    PinClear SPI_SCK_Pin                        ' Make sure the CLK pin is low before the loop starts
    For bLoop = 7 To 0 Step -1                  ' Single byte SPI loop
        Rol pValue                              ' Shift the MSB into the carry flag
        SetPin SPI_MOSI_Pin                     ' \
        If STATUSbits_C = 0 Then                ' |
            ClearPin SPI_MOSI_Pin               ' | Put the current outgoing bit on MOSI
        EndIf                                   ' /
        PinSet SPI_SCK_Pin                      ' Set the SCK pin high
        DelayCS cSPI_Delay                      ' A delay between the clock cycles
        PinClear SPI_SCK_Pin                    ' Set the SCK pin low
        DelayCS cSPI_Delay                      ' A delay between the clock cycles
    Next
EndProc

'-----------------------------------------------------------------------------
' Read an 8-bit value using the SPI mode 0 protocol (MSB first)
' Input     : None
' Output    : Returns the 8-bit value received
' Notes     : SCK is idle-low, and bits are latched on SCK rising
'
Proc SPI_Mode0_Read8(), Byte
    Dim bLoop As Byte

    PinClear SPI_SCK_Pin                        ' Make sure the CLK pin is low before the loop starts
    PinSet SPI_MOSI_Pin                         ' Set the MOSI pin
    For bLoop = 7 To 0 Step -1                  ' Single byte SPI loop
        PinSet SPI_SCK_Pin                      ' Set the SCK pin high
        DelayCS cSPI_Delay                      ' A delay between the clock cycles
        Result.0 = SPI_MISO_Pin                 ' Capture the current bit on MISO
        Result = Result << 1                    ' Shift left for MSB first
        PinClear SPI_SCK_Pin                    ' Set the SCK pin low
        DelayCS cSPI_Delay                      ' A delay between the clock cycles
    Next
EndProc

'-----------------------------------------------------------------------------
' Setup the pins used for the SPI interface
' Input     : None
' Output    : None
' Notes     : SPI_SCK_Pin connects to the slave peripheral's SCK line
'           : SPI_MOSI_Pin connects to the slave peripheral's MOSI (Master Out Slave In) line
'           : SPI_MISO_Pin connects to the slave peripheral's MISO (Master In Slave Out) line
'           : SPI_CS_Pin connects to the slave peripheral's CS line
'
Proc SPI_Setup()
    PinLow SPI_SCK_Pin
    PinOutput SPI_MOSI_Pin
    PinInput SPI_MISO_Pin
    PinHigh SPI_CS_Pin
EndProc

'---------------------------------------------------------------------------------------
' Configure for internal 7.37MHz oscillator with PLL
' OSC pins are general purpose I/O
'
    Config FBS = BWRP_WRPROTECT_OFF
    Config FGS = GWRP_OFF
    Config FOSCSEL = FNOSC_FRCPLL, IESO_OFF
    Config FOSC = POSCMD_NONE, OSCIOFNC_ON, IOL1WAY_OFF, FCKSM_CSECME
    Config FWDT = WDTPOST_PS256, WINDIS_OFF, FWDTEN_OFF
    Config FPOR = FPWRT_PWR1, ALTI2C_OFF
    Config FICD = ICS_PGD1, JTAGEN_OFF

Wimax

Thanks a lot Les, I will definitely try it! It's great to read the software (firmware) you write because it is structured in a very elegant and precise way (exactly the opposite of what I do  ;D )!

Wimax

I think that as I'm using the external oscillator I will have to modify the Fuses settings slightly.

Wimax

I tried, but couldn't get it to work, is the read/write mode the same as the Shin/Shout commands ? :'(