SD Card, PPS and the 18f26K40

General discussion relating to the library modules supplied with the compiler

Moderators: David Barker, Jerry Messina

Gunplumber
Posts: 38
Joined: Wed Nov 02, 2022 10:31 am

SD Card, PPS and the 18f26K40

Post by Gunplumber » Fri Dec 16, 2022 5:56 am

Hi guys

Once again the 18F26K40 is giving me grief!
I am trying to get the SD card module to work and so far it's been very frustrating.
I have this exact code working with a 18F252 and opening files etc, but it fails to work with the 18F26K40.. Given my previous other issues with the PPS module, i suspect i haven't got the port pins set correctly.. Here's my code, can someone double check i have it correct??

Code: Select all

#option digitalio_init=true
#option SD_SPI = MSSP1
#option SD_CS =  PORTC.2
#option SD_DI =  PORTC.5
#option SD_CLK = PORTC.3
#option SD_D0 =  PORTC.4
#option SD_SPI_SPEED = spiOscDiv4 


Sub InitPPS()    
    pps.unlock()
        'Module: MSSP1
    SSP1DATPPS = $0014    'RC4 > SDI1
    RC3PPS = $000F    'SCL1 > RC3
    SSP1CLKPPS = $0013    'RC3 > SCL1 (bidir)
    RC5PPS = $0010    'SDO1 > RC5
    'Module: MSSP1 extra settings
    Output(PORTC.3)    'Set I2C pin as output
    pps.lock()
End Sub


SetAllDigital()
Low (LED)
TRISB = %00000000                   //set port b as outputs
PORTB =127                          //set ADC at mid point
Output(PORTC.2)
Output(PORTC.5)
Output(PORTC.3)
Input(PORTC.4)
InitPPS()

Timer = TimerReload                  //load Timer
TimerOn = False                         // stop timer initially
Enable(OnTimer)                         // assign the interrupt handler
TimerEnabled = True  
Read_pointer=0
                  

Cycle=SD.Init()                                  //initilise SD card. 
If Cycle=0 Then 
    Cls
    WriteAt (1,1,"SD  Initialized ")
Else
    Cls
    WriteAt (1,1,"Init failed")
    WriteAt (2,1,DecToStr(Cycle,2," ") )
End If



The SD card fails to initialize with a #10 error, and when i check the port pins with my logic analyzer i get no clock output at all..

Any ideas?

Cheers
Lee

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: SD Card, PPS and the 18f26K40

Post by Jerry Messina » Fri Dec 16, 2022 1:50 pm

You might want to try this basic setup and see if/how it works

Code: Select all

device = 18F26K40
clock = 64

include "intosc.bas"

dim LED as PORTB.0          // <<<<<<<< assume there's an LED on RB0

#option digitalio_init=true		// automatically call setalldigital at startup
include "setdigitalio.bas"

// from PPStool
include "pps.bas"
#option SPI_SCK = PORTC.3
#option SPI_SDI = PORTC.4
#option SPI_SDO = PORTC.5
include "SPI.bas"

#option SD_SPI = MSSP1			// use SPI IO pin definitions above
#option SD_CS =  PORTC.2
#option SD_SPI_SPEED = spiOscDiv4 
include "SDFileSystem.bas"

public sub InitPPS()
    pps.unlock()

    'Module: MSSP1
    RC3PPS = $000F        'SCK1 > RC3
    SSP1CLKPPS = $0013    'RC3 > SCK1 (bidir)
    SSP1DATPPS = $0014    'RC4 > SDI1
    RC5PPS = $0010        'SDO1 > RC5

    pps.lock()
end sub

low(LED)
InitPPS()

delayms(500)						// allow time for the SD card to power up

If SD.Init() = SD.errOK Then        //initilise SD card
    high(LED)
endif

When you select '#option SD_SPI = MSSP1' or 'MSSP2' then the sd lib uses the spi.bas/spi2.bas lib, so you want to use the pin setups for those modules.

The order of 'includes' can be important... "include SDFileSystem.bas" adds an initializer that automatically runs at startup to setup the SPI, and that's going to run before the InitPPS() call gets a chance to run.

Gunplumber
Posts: 38
Joined: Wed Nov 02, 2022 10:31 am

Re: SD Card, PPS and the 18f26K40

Post by Gunplumber » Sat Dec 17, 2022 12:11 pm

Hi Jerry

Thank you once again for offering some help..
I have copied your sample code verbatim but still get the failure to initialize, as well as no output from the clock pin.
However i have been able to test some more of the hardware by using some SPI commands and can indeed get the clock and data lines to work so i am confident that the PPS is set correctly..
I then therefor suspected i had the card wired incorrectly, but i've been able to prove that it is correct because i can plug in an 18F252 with my old code and it reads the SD card fine so hardware seems fine.
I now suspect come kind of configuration issue with the SD card module that's not configured correctly with the 26K40?

Cheers
Lee

Code..

Code: Select all

Include "intosc.bas"
// some LCD options...
#option digitalio_init=true
Include "setdigitalio.bas"

Include "pps.bas"
#option SPI_SCK = PORTC.3
#option SPI_SDI = PORTC.4
#option SPI_SDO = PORTC.5
Include "SPI.bas"

#option SD_SPI = MSSP1
#option SD_CS =  PORTC.2
#option SD_SPI_SPEED = spiOscDiv64 
Include "SDFileSystem.bas"

#option LCD_DATA = PORTA.0
#option LCD_RS = PORTC.0
#option LCD_EN = PORTC.1
Include "LCD.bas" 

Include "convert.bas"
Include "utils.bas"

Dim Led as portA.5
Sub InitPPS()    
    pps.unlock()
        'Module: MSSP1
    RC3PPS = $000F        'SCK1 > RC3
    SSP1CLKPPS = $0013    'RC3 > SCK1 (bidir)
    SSP1DATPPS = $0014    'RC4 > SDI1
    RC5PPS = $0010        'SDO1 > RC5
    pps.lock()
End Sub

Start:
Low (LED)
TRISB = %00000000                   //set port b as outputs
PORTB =127                          //set ADC at mid point
Output(PORTC.3)
Output(PORTC.2)
Output(PORTC.5)
Input(PORTC.4)

InitPPS()

 SPI.SetAsMaster(spiOscDiv64)			//This code works as it should and outputs clock and data.. 
 SPI.SetClock(spiIdleLow,spiRisingEdge)
 SPI.Enabled=true
 SPI.WriteByte(46)

 DelayMS(2000)




Cycle=SD.Init()                              //initilise SD card here but fails with error 10.. 
If Cycle=0 Then 
    Cls
    WriteAt (1,1,"SD  Initialised ")
Else
    Cls
    WriteAt (1,1,"Init failed")
    WriteAt (2,1,DecToStr(Cycle,2," ") )
End If

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: SD Card, PPS and the 18f26K40

Post by Jerry Messina » Sat Dec 17, 2022 1:22 pm

I'll dig up a K40 and see what's going on...

What clock speed are you running at?

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: SD Card, PPS and the 18f26K40

Post by Jerry Messina » Sat Dec 17, 2022 3:08 pm

Ok, I see what the problem is... it's not necessarily the K40 that's the cause, it's the use of PPS for the SPI.

When the SD is first initialized it uses bit-banging to send the init sequence to the SD card, after which it enables the SPI hdw.
This is done in SD.InitSequence(). That's pretty standard because until it's setup the SPI clock has to be a really low frequency (generally in the 100-400KHz range), and most SPI peripherals don't go that slow.

The trouble is, once the pins are mapped to the SPI peripheral you can't bit-bang them... you have to reset the PPS mapping to get the pins under port control, send the init sequence, remap the PPS, and then init the SPI peripheral.

SDFileSystem.bas can handle enabling and disabling the SPI peripheral, but it doesn't know jack about PPS. It needs to have enable and disable functions for that too, along with an option to control it. I'll have to think about how to deal with that since you don't want to add the code directly into SDFileSystem.bas as each device with PPS uses different mapping, otherwise you end up with SDFileSystem having a bunch of device-specific code in it which is a nightmare to code and support. I already removed a lot of that when I changed it to use the SPI/SPI2 modules instead of having the code directly in SDFileSystem.

This would likely involve getting another module involved that would contain the SPI PPS map/unmap routines that SDFileSystem could call.
The other option is to allow the SPI setup to use 'SPI Master mode: Clock = TMR2 output/2' mode at first, but that involves getting TMR2 involved which may already be used for other things.

I'm open to suggestions...

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: SD Card, PPS and the 18f26K40

Post by Jerry Messina » Sat Dec 17, 2022 4:15 pm

Another choice would be to add two events to SDFileSystem, something like SD.PPSOpen and SD.PPSClose, which you could set to your external routines outside the SDFileSystem module.

SD.InitSequence() would use these user routines instead of code inside SDFIleSystem. That would let you add whatever code as needed... map pps/unmap pps, whatever. If you're not using PPS then you'd just leave these events undefined.

Let me mull that over...

Gunplumber
Posts: 38
Joined: Wed Nov 02, 2022 10:31 am

Re: SD Card, PPS and the 18f26K40

Post by Gunplumber » Sat Dec 17, 2022 10:10 pm

Hi Jerry

After posting last night i did some more digging through the SD module and did notice the bit banging. It never occurred to me that manual control of the port pins would fail because they were PPS mapped.. :o

After my morning coffee this morning i wondered if we could get rid of the bit banging (or at least turn it off), use the MSSP and simply reduce the system osc while the init sequence runs then throttle back up to full freq? With the 26K40 one can reduce the system clock to 1mhz, which would then be further divided by 4 at the fastest SD card speed which would yield 250 kHz during the init sequence?

I realize this may not be applicable for every device though.

Thoughts?

In the mean time how does one modify a system module like SD? From my understanding the only way to do it is to cut and paste the entire module into a new file and re-name it, then include the new module?


Cheers
Lee

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: SD Card, PPS and the 18f26K40

Post by Jerry Messina » Sat Dec 17, 2022 11:54 pm

I have no idea if something like that would work or not.

If all you need is a quick fix for what you're using now, then the easiest thing that might work is to move the InitPPS routine and call from the main program into the SDFileSystem InitSequence() function, maybe something like this:

Code: Select all

....
    SendByte($FF)                                               // Clock SD/MMC to complete
    if (Disk.CardType > 0) then
        result = true
      #if (SD_SPI in (MSSP1, MSSP2, SPI1XV, SPI2XV))            // hardware version
        InitPPS()			// ADD CALL TO SETUP PPS
        InitSPIPort()                                           // Setup MSSP module & turn on
      #endif
        Disk.SlowSPI = 0                                        // Set SPI to fast mode
    endif
end function
In the mean time how does one modify a system module like SD?
There are different ways to do this, but the best way is to make a copy of the file and put it into the UserLibrary folder.
That will override the copy in the Library folder. You can make changes to that file instead, and the original will always be there untouched.

User avatar
David Barker
Swordfish Developer
Posts: 1214
Joined: Tue Oct 03, 2006 7:01 pm
Location: Saltburn by the Sea, UK
Contact:

Re: SD Card, PPS and the 18f26K40

Post by David Barker » Sun Dec 18, 2022 10:29 am

> ... make a copy of the file and put it into the
> UserLibrary folder. That will override the copy in the Library folder.
> You can make changes to that file instead, and the original will always
> be there untouched.

This is the correct and best way of doing it...

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: SD Card, PPS and the 18f26K40

Post by Jerry Messina » Sun Dec 18, 2022 3:22 pm

Here's a new version of SDFileSystem.bas that allows for mapping and unmapping the SPI PPS.
Unzip it and put it in the UserLibrary (or directly into your main program folder if you just want to test it out)

To use it you define two event routines in your main program and then the SD module will use these callbacks to enable and disable the PPS mapping for the SPI hdw when SD.Init() is called.

Here's an example:

Code: Select all

device = 18F27K40
clock = 64

Include "intosc.bas"
#option digitalio_init=true
Include "setdigitalio.bas"

Include "pps.bas"
#option SPI_SCK = PORTC.3
#option SPI_SDI = PORTC.4
#option SPI_SDO = PORTC.5
Include "SPI.bas"

#option SD_SPI = MSSP1
#option SD_CS =  PORTC.2
#option SD_SPI_SPEED = spiOscDiv16      // SPI clk = 64/16 (4MHz)
#option SD_INITIO = false   // might as well skip startup IO pin setup if it requires PPS to be mapped first
Include "SDFileSystem.bas"

#option LCD_DATA = PORTA.0
#option LCD_RS = PORTC.0
#option LCD_EN = PORTC.1
Include "LCD.bas" 
Include "convert.bas"
Include "utils.bas"

dim cycle as byte

//
// SDFileSystem v4.1.8 defines two user callback events - OnMapSPIPPS and OnUnmapSPIPPS
// SD.InitSequence() will call these to enable/disable PPS mapping during SD.Init()
//
// SD callback event to map MSSP1(SPI1) via PPS
event mapSPI1PPS()
    pps.unlock()
    RC3PPS = $0F        'SCK1 > RC3
    SSP1CLKPPS = $13    'RC3 > SCK1 (bidir)
    SSP1DATPPS = $14    'RC4 > SDI1
    RC5PPS = $10        'SDO1 > RC5
end event

// SD callback event to unmap MSSP1(SPI1) PPS outputs (to allow bit-banging)
// mapped inputs don't matter, just outputs
event unmapSPI1PPS()
    pps.unlock()
    RC3PPS = 0      // return SCK1 back to LAT
    RC5PPS = 0      // return SDO1 back to LAT
end event

Start:
// setup SD module PPS events
SD.OnMapSPIPPS = mapSPI1PPS
SD.OnUnmapSPIPPS = unmapSPI1PPS

DelayMS(2000)      // allow some startup time

Cycle=SD.Init()
If Cycle=0 Then 
    Cls
    WriteAt (1,1,"SD  Initialised ")
Else
    Cls
    WriteAt (1,1,"Init failed")
    WriteAt (2,1,DecToStr(Cycle,2," ") )
End If
Try it and let me know how it works out...
Attachments
SDFileSystem_v18.zip
(31.64 KiB) Downloaded 201 times

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: SD Card, PPS and the 18f26K40

Post by Jerry Messina » Sun Dec 18, 2022 4:05 pm

note: the above sets the SPI clk to 4MHz (assuming 'clock=64')

You may have issues with setting the SPI clk to 16MHz (#option SD_SPI_SPEED = spiOscDiv4).
If you do, the K40 is one of the devices that can use the SSPADD reg as a baudrate divisor.
Setting '#option SD_SPI_SPEED = spiOscSSPADD' will get you an SPI clk of 8MHz

Gunplumber
Posts: 38
Joined: Wed Nov 02, 2022 10:31 am

Re: SD Card, PPS and the 18f26K40

Post by Gunplumber » Tue Dec 20, 2022 11:20 am

Hi Guys
Sorry for the delay getting back to you.
Thanks for all your efforts in getting the SD module up and running on this device.
Jerry i have taken your advice and added the InitPPS routine into the SDInit routine and I can now initialize and open files.
I've also now downloaded your new SDFilesystem.bas and installed it into the user library and again it works as intended and i can initialize and open files.
However i have discovered another issue in that it appears can only ready 4096 bytes from a file. After that, the SD.ReadByte() command returns zeros until the EOF condition.. I have confirmed this on several files all larger than 4K..
I have had a look through the readbyte routine, but it's all a bit over my head once we get into SD card formats, sectors etc.


Cheers
Lee

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: SD Card, PPS and the 18f26K40

Post by Jerry Messina » Tue Dec 20, 2022 11:51 am

Try disabling the optimization code... add

Code: Select all

#option SD_OPTIMIZE = false
before the 'include sdfilesystem'. If that fixes it then I screwed up the optimizations I added.

I'll see if I can dig up some hdw to actually test it on...

Gunplumber
Posts: 38
Joined: Wed Nov 02, 2022 10:31 am

Re: SD Card, PPS and the 18f26K40

Post by Gunplumber » Tue Dec 20, 2022 12:23 pm

Jerry

I just did a quick check with the optimization turned off and that made no difference to the 4096 byte problem..

Cheers
Lee

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: SD Card, PPS and the 18f26K40

Post by Jerry Messina » Tue Dec 20, 2022 1:26 pm

Thanks for checking Lee. At least that rules out most of the code changes I did.
With that option off, the code should have been pretty similar to the older versions (basically v4.1.4).

I'll have a look

Post Reply