Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

SD Card and SPI Communications

Status
Not open for further replies.

Mity Eltu

Member
OK. I have just spent the better part of the day banging on this project and have found something that is either really irritating and incredibly frustrating or is a serious problem for oshonsoft, or I may just be an idiot and need help.

This is the story...

18F4520, 8MHz internal osc. LCD with 4 bit low on portd.
I needed to be able to sample a thermocouple that will be using SPI to communicate with the PIC and then store the data on an SD card for later analysis on a PC. No problem.

I was able to get the thermocouple working while displaying the current temp on the LCD within a few minutes. I am using the MAX6675 which incorporates a 12 bit A/D and cold junction compensation - kill 2 birds with one stone, right?

Next came the SD card. I was able to get the SD card working great a few weeks ago. but then I added the SAME CODE from the working project into this one with the thermocouple. No dice. I checked, rechecked and double rechecked about a hundred times today. The SD card would not even be recognized. I am using a considerable portion of the code found on the oshosoft website for the SD Card Example (https://www.oshonsoft.com/sdcard.php). Like I said, it worked great when it was by itself. Logged data and was able to get the file off the card with a pc. No problem.

So I decided to do a little side by side comparison of the code. The ONLY difference between the 2 was the SPI setup in the code with the thermocouple. I HAVE to have the SPI working to get data from the thermocouple. Apparently, the sdcardinit command does all this for the sd card. As soon as I removed the lines for SSPCON1 and SSTSTAT, the SD card started working.

I have not yet had the time (as I have spent the ENTIRE day on this one part) to see if this has made it impossible for the thermocouple to communicate - though I suspect it has.

This is a serious problem as I need the communications for both in the same project and on the same chip. Has anyone come across this before? Is there a fix? Am I just an idiot and the SPI communications will work just fine wihtout the SSPCON1 and SSPSTAT registers being set?

What say you all?
 
hi Mity,
I wrote some Oshonsoft 18F4520 routines for the SD card some time ago, I had some problems with some Basic commands listed in the manual, that the compiler would not recognise.
I contacted Vladimir with a Bug report, he replied I should fit more decoupling caps!, how that would solve the compiler problem is anyone's guess.!

Sometimes the SD card would record and read the Formatted Data and other times it would lock up. [I didn't want to use the Raw data option ]

If you post your SD coding, full program, I will set up my development board and try the code.

E
 
One of the biggest problems with SD cards is that some struggle at 3v3.... When you use two diodes from a 5v rail the SD can get 3v6 ~ 3v8 which gives "Non Branded" SD's a bit more of a boost...

The best solution is to run little units like this on a 3v7 lithium battery.... Plenty of power.. Just make sure you use 1uf decoupling caps... 0.1uf isn't really big enough as when the card starts writing / reading the power really jumps up!
 
I'll try this when I get back to work Monday. I'll post the segments of code that work independently and then try to use them other. Hopefully the SPI will work with the sd card AND the thermocouple in the same circuit.

Thanks for the advice.
 
OK, Attached is the code I am using. It does very little at the moment, but it does recognize the SD card. I have another program that I have used that is similar to this that will write the data into a CSV text file. This is a stripped down version of that one.
The problem now is that the program locks up at the WHILE SSPSTAT.0 = 0 command. I am guessing that since the SPI has not been set up using the 2 registers, the MSSP module doesn't know what to do with the commands. That means I will have to go back to bit banging all this SD card stuff. THAT's going to be an issue.

If you can find a problem with the code that is causing this issue, I would really appreciate it. In the mean time I am going to start working on a bit bang version of the SPI code that maybe I can get to work with the sd card. This is a serious flaw with the compiler, IMO, if the SPI commands can't be used with other SPI devices when an SD card is used.

On a side note, the power supply I am using shuld be capable of powering this and many other devices simultaneously. I am using an 480W ATX power supply that is properly filtered and decoupled. The scope shows no ripple/noise on the power supply rails when the chip is switching multiple led's simultaneously.


Code:
'18F4520
'internal 8 MHz clock
'Full size SD Card Reader
'porte2 = chip select SD card
'porte0 = chip select MAX6675
 
 
'NOTE
'This program worked as expected
'AFTER I REMOVED THE SPI SETUP PARAMETERS
 
 
'12/14/15
'adding thermocouple solution using MAX6675
'uses SPI - testing to see if this will work with the
'existing sd card configuration
'If this does not work, I will try the sd card using a
'direct interface as opposed to the card module in
'curretn use
 
Define CONFIG1L = 0x00
Define CONFIG1H = 0x08
Define CONFIG2L = 0x19
Define CONFIG2H = 0x00
Define CONFIG3L = 0x00
Define CONFIG3H = 0x85
Define CONFIG4L = 0x80
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40
 
'LCD Configuration - 4-bit lower
Define LCD_LINES = 2
Define LCD_CHARS = 16
Define LCD_BITS = 4
Define LCD_DREG = PORTD
Define LCD_DBIT = 4
Define LCD_RSREG = PORTD
Define LCD_RSBIT = 0
Define LCD_RWREG = PORTD
Define LCD_RWBIT = 1
Define LCD_EREG = PORTD
Define LCD_EBIT = 2
 
'SPI Configuration
Define SPI_CS_REG = PORTE
Define SPI_CS_BIT = 2
Define SPI_SCK_REG = PORTC
Define SPI_SCK_BIT = 3
Define SPI_SDI_REG = PORTC
Define SPI_SDI_BIT = 4
Define SPI_SDO_REG = PORTC
Define SPI_SDO_BIT = 5
'SPIINIT is NOT used in the program
 
Define CLOCK_FREQUENCY = 8
 
'global variables
Dim flags As Byte
 
'variables required for MAX6675 sections
Dim mb1 As Byte
Dim mb2 As Byte
Dim max6675 As Word
Dim temp As Single
Dim deg As Byte
 
main:
    OSCCON = 0x72  'internal 8MHz
    Gosub setup
    Lcdinit 0
 
 
    Lcdout "Ready"
    WaitMs 1000
    Lcdcmdout LcdClear
 
    SDCardInit
        WaitMs 2000
        Lcdcmdout LcdLine1Clear
        Lcdcmdout LcdLine1Home
        If sd_status.sd_error = 1 Then Lcdout "Unknown Card"
        If sd_status.sd_mmc = 1 Then Lcdout "MMC Card"
        If sd_status.sd_sd = 1 Then Lcdout "SD Card"
        If sd_status.sd_sdsc = 1 Then Lcdout "SDSC Card"
        If sd_status.sd_sdhc = 1 Then Lcdout "SDHC Card"
 
    Lcdcmdout LcdLine2Clear
loop:
    If flags.0 = 1 Then
        flags.0 = 0
        While PORTB.0 = 1
        Wend
   
        WaitMs 200
        Toggle PORTE.1
   
        Gosub get_temp
        Gosub convert
   
        Lcdcmdout LcdLine2Clear
        Lcdout #temp
        Lcdout deg, "C  "
   
        temp = temp * 1.8 + 32
        Lcdout #temp, deg, "F"
    Endif
    Goto loop  'infinite loop
End                                          
 
 
setup:
    INTCON = 0xd0  'int0 en
    INTCON2 = 0xc0  'pull ups disabled, int0 on rising egde
 
    CCP1CON = 0x00  'cap / comp off
    CCP2CON = 0x00
 
    'SSPCON1 = 0x21  'spi on, fosc/16, clk idle state low
    'SSPSTAT = 0x40  'sample in middle, cke=1 - xfer on clk high to low
 
    ADCON0 = 0x00  'A/D off
    ADCON1 = 0x0f  'all digital
 
    CMCON = 0x07  'comp off, digital io
    CVRCON = 0x00
   
    HLVDCON = 0x00  'Low volt detect off
 
    TRISA = 0x00
    TRISB = 0x01
    TRISC = 0x00
    TRISC.4 = 1  'sdi input
    TRISD = 0x00
    TRISE = 0x00
 
    LATA = 0x00
    LATB = 0x00
    LATC = 0x00
    LATD = 0x00
    LATE = 0x0f  'porte2 set for sd card chip select
 
    flags = 0x00
    deg = 0xdf  'degree symbol
Return                                       
 
 
get_temp:
        'get new temperature reading and store in eeprom
        'MAX6675 temperature reading
        'this chip has no SPI input
        'all this chip is expecting is a clock source
        PORTE.0 = 0  'chip select
 
        SSPBUF = 0x11  'send dummy byte to receive first byte from chip
        While SSPSTAT.0 = 0
        Wend
        mb1 = SSPBUF
        SSPSTAT.0 = 0
 
        SSPBUF = 0x22  'send dummy byte to receive second byte from chip
        While SSPSTAT.0 = 0
        Wend
        mb2 = SSPBUF
        SSPSTAT.0 = 0
   
        PORTE.0 = 1  'deselct chip
Return                                       
 
 
convert:
        max6675.HB = mb1
        max6675.LB = mb2
        max6675 = ShiftRight(max6675, 3)
        max6675 = max6675 - 5
   
        mb1 = max6675.HB
        mb2 = max6675.LB
   
        temp = max6675 / 4
Return                                       
 
 
On High Interrupt
    If INTCON.1 = 1 Then  'int0
        INTCON.1 = 0
        flags.0 = 1
    Endif
Resume
 
Last edited:
OK, WOW. I just finished readin a ton of stuff on SPI commincations and there is no way I am gouing to be able to bitbang an spi platform that will permit me to write a CSV file onto this sd card. Frankly, I aint smart enough for that. I'm going to submit a possible bug report to vladimir and hope there is a solution, otherwise, I'll HAVE to abandon oshonsoft in favor of a platform that will alow me to use the spi bus for sd cards AND other peripherals at the same time.

Hope someone out there knows how to fix this. I really don't want to find yet another compiler.
 
I have been thinking. I can find no way to force the SPI module to work with both the SD card and a separate peripheral that uses SPI communications. Something about the differing setups wil not allow them to work at the same time. I tried al kinds of combinations of the code to try to force it. I do have them working independently.

This one takes readings from a dallas temperatre 1-wire sensor and stores data on the SD card without any problems:
Code:
Define SPI_CS_REG = PORTC
Define SPI_CS_BIT = 2
Define SPI_SCK_REG = PORTC
Define SPI_SCK_BIT = 3
Define SPI_SDI_REG = PORTC
Define SPI_SDI_BIT = 4
Define SPI_SDO_REG = PORTC
Define SPI_SDO_BIT = 5
 
Define LCD_LINES = 2
Define LCD_CHARS = 16
Define LCD_BITS = 4
Define LCD_DREG = PORTD
Define LCD_DBIT = 4
Define LCD_EREG = PORTD
Define LCD_EBIT = 3
Define LCD_RSREG = PORTD
Define LCD_RSBIT = 2
Define LCD_RWREG = PORTD
Define LCD_RWBIT = 1
 
Define 1WIRE_REG = PORTE
Define 1WIRE_BIT = 0
 
Define CLOCK_FREQUENCY = 8
'Define SIMULATION_WAITMS_VALUE = 10
 
Dim finish As Bit
Dim temp_lsb As Byte
Dim temp_msb As Byte
Dim dat As Byte
Dim tenths As Single
Dim temp_out As Single
Dim loop As Bit
Dim lp_cnt As Byte
Dim end_loop As Bit
Dim e_loop As Bit
Dim ad_res As Long
Dim tc_temp As Single
 
 
main:
    OSCCON = 0x72  'internal, 8MHz
    Gosub setup
 
    Lcdinit LcdCurBlink
 
    WaitMs 2000
    Lcdcmdout LcdClear
    Lcdout "UL248 Fuse Test"
    Lcdcmdout LcdCurOff
   
    Gosub sd_start
   
    Lcdcmdout LcdClear
    Lcdout "Current Temp"
   
    While loop
        ADCON0.1 = 1  'start a/d
        1wireInit
        1wireSendByte 0xcc, 0x44
        WaitMs 750
lp:
        1wireGetBit finish
        If finish = 0 Then Goto lp
        1wireInit
        1wireSendByte 0xcc, 0xbe
        1wireGetByte temp_lsb, temp_msb
        'Lcdout #temp_msb, " ", #temp_lsb
        Lcdcmdout LcdLine2Home
        dat = temp_lsb
        dat = dat And 0x0f
        tenths = dat * 0.062500
        temp_lsb = ShiftRight(temp_lsb, 4)
        temp_msb = ShiftLeft(temp_msb, 4)
        temp_lsb = temp_lsb Or temp_msb
        temp_out = temp_lsb + tenths
       
        WaitMs 200
        'get a/d result and convert to temp and
        'subtract cold junction temp
        ad_res.LB = ADRESL
        ad_res.HB = ADRESH
        tc_temp = ad_res * 0.00488280
        tc_temp = tc_temp / 416
       
        Call sd_t_out(temp_out)  'write degC to sd card
       
        Lcdout #temp_out, "C  "
        temp_out = temp_out * 1.8000 + 32
        Lcdout #temp_out, "F"
       
        Call sd_t_out(temp_out)  'write degF to sd card
       
        SDCardFAT32FileWrite CrLf  'new line
        Toggle LATA.3  'heartbeat
        WaitMs 3000
       
        lp_cnt = lp_cnt + 1
        If lp_cnt = 20 Then
            SDCardFAT32FileClose
            If sd_fat32_status.sd_fat32_wr_opened = 0 Then
                Lcdcmdout LcdClear
                Lcdout "UL248.txt clsd!"
            Endif
            While end_loop
            Wend
        Endif
    Wend
End                                              
 
 
setup:
    INTCON = 0x00  'glbl/periph int dis
 
    CCP1CON = 0x00  'cap/comp off
 
    ADCON0 = 0x01  'a/d off
    ADCON1 = 0x0e  'an0
    ADCON2 = 0x91  'rt just
   
    CMCON = 0x07
   
    CVRCON = 0x00
   
    HLVDCON = 0x00
   
    'all output
    TRISA = 0x01
    LATA = 0x00
   
    TRISB = 0x00
    LATB = 0x00
   
    TRISC = 0x00
    LATC = 0x00
   
    TRISD = 0x00
    LATD = 0x00
   
    TRISE = 0x00
    LATE = 0x00
   
    lp_cnt = 0
    loop = 1
    end_loop = 1
    e_loop = 1
Return                                           
 
 
sd_start:
    SDCardInit
 
    WaitMs 2000
    Lcdcmdout LcdClear
    If sd_status.sd_error = 1 Then
        Lcdout "Unknown card!"
        While e_loop = 1
        Wend
    Endif
    If sd_status.sd_mmc = 1 Then Lcdout "MMC card!"
    If sd_status.sd_sd = 1 Then Lcdout "SD card!"
    If sd_status.sd_sdsc = 1 Then Lcdout "SDSC card!"
    If sd_status.sd_sdhc = 1 Then Lcdout "SDHC card!"
    WaitMs 1000  'time to reseat if needed
   
    SDCardFAT32Init
    Lcdcmdout LcdClear
    If sd_fat32_status.sd_fat32_error = 0 Then
        Lcdout "FAT32 initlized!"
    Endif
   
    WaitMs 2000
    SDCardFAT32FileDelete "UL248.txt"
    If sd_fat32_status.sd_fat32_deleted = 1 Then
        Lcdcmdout LcdClear
        Lcdout "File Deleted"
    Endif
    SDCardFAT32FileCreate "UL248.txt"
    Lcdcmdout LcdClear
    If sd_fat32_status.sd_fat32_wr_opened = 1 Then
        Lcdout "UL248.txt open!"
    Endif
    WaitMs 2000
   
    SDCardFAT32FileWrite "degC,  degF", CrLf
Return                                           
 
 
Proc sd_t_out(dat As Single)
'dat is composed of degC in xxx.xxxx format
    Dim lng_num_str As String
    Dim new_cnt As Single
    Dim num_part As String
    Dim digit As String
   
    lng_num_str = #dat
    new_cnt = dat
       
        If new_cnt >= 0 And new_cnt < 10 Then
            digit = LeftStr(lng_num_str, 1)
            SDCardFAT32FileWrite digit, "."
            num_part = LeftStr(lng_num_str, 3)
            digit = RightStr(num_part, 1)
            SDCardFAT32FileWrite digit
            num_part = LeftStr(lng_num_str, 4)
            digit = RightStr(num_part, 1)
        Endif
       
        If new_cnt >= 10 And new_cnt < 100 Then
            digit = LeftStr(lng_num_str, 1)
            SDCardFAT32FileWrite digit
            num_part = LeftStr(lng_num_str, 2)
            digit = RightStr(num_part, 1)
            SDCardFAT32FileWrite digit, "."
            num_part = LeftStr(lng_num_str, 4)
            digit = RightStr(num_part, 1)
            SDCardFAT32FileWrite digit
            num_part = LeftStr(lng_num_str, 5)
            digit = RightStr(num_part, 1)
        Endif
       
        If new_cnt >= 100 Then
            digit = LeftStr(lng_num_str, 1)
            SDCardFAT32FileWrite digit
            num_part = LeftStr(lng_num_str, 2)
            digit = RightStr(num_part, 1)
            SDCardFAT32FileWrite digit
            num_part = LeftStr(lng_num_str, 3)
            digit = RightStr(num_part, 1)
            SDCardFAT32FileWrite digit, "."
            num_part = LeftStr(lng_num_str, 5)
            digit = RightStr(num_part, 1)
            SDCardFAT32FileWrite digit
            num_part = LeftStr(lng_num_str, 6)
            digit = RightStr(num_part, 1)
        Endif
        SDCardFAT32FileWrite digit, ", "
End Proc


This one grabs data from a MAX6675 over SPI without any problem
Code:
'LCD Configuration - 4-bit lower
Define LCD_LINES = 2
Define LCD_CHARS = 16
Define LCD_BITS = 4
Define LCD_DREG = PORTD
Define LCD_DBIT = 4
Define LCD_RSREG = PORTD
Define LCD_RSBIT = 0
Define LCD_RWREG = PORTD
Define LCD_RWBIT = 1
Define LCD_EREG = PORTD
Define LCD_EBIT = 2
 
'SPI Configuration
Define SPI_CS_REG = PORTE
Define SPI_CS_BIT = 2
Define SPI_SCK_REG = PORTC
Define SPI_SCK_BIT = 3
Define SPI_SDI_REG = PORTC
Define SPI_SDI_BIT = 4
Define SPI_SDO_REG = PORTC
Define SPI_SDO_BIT = 5
SPIPrepare
 
Define CLOCK_FREQUENCY = 40
Define SINGLE_DECIMAL_PLACES = 2
 
'global variables
Dim flags As Byte
Dim i As Byte
Dim mb1 As Byte
Dim mb2 As Byte
Dim max6675 As Word
Dim temp As Single
Dim t_av As Single
Dim x As Byte
 
main:
    OSCCON = 0x00  'external osc
    Gosub setup
   
    Lcdinit 0
   
    Lcdout "Ready"
    WaitMs 1000
 
    Lcdcmdout LcdClear
    Lcdout "Temperature:"
   
    Gosub get_temp
    Gosub convert
    Lcdcmdout LcdLine2Home
    Lcdout #temp
    x = 0xdf
    Lcdout x, "C  "
   
    temp = temp * 1.8 + 32
    Lcdout #temp, x, "F"
   
loop:
    If flags.0 = 1 Then  'interrupt has occurred
        flags.0 = 0
        Gosub write_data
    Endif
   
    t_av = 0
    For i = 1 To 5
        Gosub get_temp
        Gosub convert
        t_av = t_av + temp
        WaitMs 400
    Next i
   
    temp = t_av / 5
   
    Lcdcmdout LcdLine2Clear
    Lcdout #temp
    Lcdout x, "C  "
   
    temp = temp * 1.8 + 32
    Lcdout #temp, x, "F"
   
    For i = 0 To 2  'blink to show complete
        LATE.1 = 1
        WaitMs 50
        LATE.1 = 0
        WaitMs 50
    Next i
    Goto loop  'infinite loop
End                                              
 
 
setup:
    INTCON = 0xd0  'int0 en
    INTCON2 = 0xc0  'pull ups disabled, int0 on rising egde
 
    CCP1CON = 0x00  'cap / comp off
    CCP2CON = 0x00
   
    SSPCON1 = 0x21  'spi on, fosc/16, clk idel state low
    SSPSTAT = 0x40  'sample in middle, cke=1 - xfer on clk high to low
   
    ADCON0 = 0x00  'A/D off
    ADCON1 = 0x0f  'all digital
   
    CMCON = 0x07  'comp off, digital io
    CVRCON = 0x00
       
    HLVDCON = 0x00  'Low volt detect off
   
    TRISA = 0x00
    'LATA.5 = 1
    TRISB = 0x01
    TRISC = 0x00
    'TRISC.4 = 1  'sdi input
    TRISD = 0x00
    TRISE = 0x00
   
    LATA = 0x00
    LATB = 0x00
    LATC = 0x00
    LATD = 0x00
    LATE = 0x01  'porte0 set for MAX6675 chip select
 
    flags = 0x00
Return                                           
 
 
get_temp:
        'get new temperature reading and store in eeprom
        'MAX6675 temperature reading
        'this chip has no SPI input
        'all this chip is expecting is a clock source
        PORTE.0 = 0  'chip select
   
        SSPBUF = 0x11  'send dummy buyte to receive first byte from chip
        While SSPSTAT.0 = 0
        Wend
        mb1 = SSPBUF
        SSPSTAT.0 = 0
   
        SSPBUF = 0x22  'send dummy buyte to receive first byte from chip
        While SSPSTAT.0 = 0
        Wend
        mb2 = SSPBUF
        SSPSTAT.0 = 0
       
        PORTE.0 = 1  'deselct chip
Return                                           
 
 
convert:
        max6675.HB = mb1
        max6675.LB = mb2
        max6675 = ShiftRight(max6675, 3)
        max6675 = max6675 - 5
       
        mb1 = max6675.HB
        mb2 = max6675.LB
       
        temp = max6675 / 4
Return                                           
 
 
write_data:
'I never got this to work - This was going to be the SD Card data logging function
Return                                           
 
 
'Proc sspsend(adr As Byte, dat As Byte)
    'PORTA.5 = 0  'chip select
   
    'SSPBUF = 0x40  'send chip id, RW bit = 0 (write)
    'While SSPSTAT.0 = 0
    'Wend
    'SSPSTAT.0 = 0
   
    'SSPBUF = adr  'send address
    'While SSPSTAT.0 = 0
    'Wend
    'SSPSTAT.0 = 0
   
    'SSPBUF = dat  'send data
    'While SSPSTAT.0 = 0
    'Wend
    'SSPSTAT.0 = 0
   
    'PORTA.5 = 1
'End Proc
 
'Function sspread(adr As Byte) As Byte
    'PORTA.5 = 0  'chip select
   
    'SSPBUF = 0x41  'send chip id, RW bit = 1 (read)
    'While SSPSTAT.0 = 0
    'Wend
    'SSPSTAT.0 = 0
   
    'SSPBUF = adr  'send address
    'While SSPSTAT.0 = 0
    'Wend
    'SSPSTAT.0 = 0
   
    'send/receive is simultaneous, so when the dummy byte is sent
    'the byte I want to receive is also being clocked in
    'See datasheet: satates "17.3 SPI MODE
    'The SPI mode allows 8 bits of data to be SYNCHRONOUSLY
    'transmitted and received simulateously
    'SSPBUF = 0xff
    'While SSPSTAT.0 = 0
    'Wend
    'SSPSTAT.0 = 0
   
    'sspread = SSPBUF
 
    'PORTA.5 = 1
'End Function
 
 
On High Interrupt
    If INTCON.1 = 1 Then  'int0
        INTCON.1 = 0
        flags.0 = 1
    Endif
Resume

I know they are for different chips, but the fact is, I can perform both functions independently. I can't get them to work on the same chip.

So, I am thinking maybe use 2 separate chips. Both would need SPI and EUSART modules. I can use one to gather data from the MAX6675 and send via USART to the second. The second then operates as master and sends data to the SD Card. This is obviously not ideal, but what do you think? Workable?
 
Ok. Finished coding 2 separate programs for 2 separate chips: 18F4550 is grabbing the data from the MAX6675 and sending via USART to 18F4520. The 18F4520 receives the data from the USART, converts it to °C and displays it on the LCD. I'll work on getting that data into the SD card tomorrow. Too tired.... head hurts.... walll... is... so... hard....

Anyway, I only had these 2 chips. I will eventually use smaller chips (28 pin narrow dip) to save some realestate. Not an ideal solution, but it seems to work. I fugure there must be a way to combine the sd spi with other peripheral devices, but it's beyond my knowledge base to find it.

I'll post the update after I get the sd card working.... notice the delusional optimism....

Thanks for the help.
 
Hi Mity,
Sorry for delayed reply.
In the Spring of this year I had all Raw, 16FAT and 32FAT programs working OK.
The only problem I had was that the Compiler did not recognise FileExist or FileAppend commands, I sent a bug report to Vlad, the reply I got was useless.

The intention was to build a weather station data logger, using a RTC DS3231, DHT22,BMP180 modules, the data recorded on the SD Card would be read by the PC, the project worked OK on the bench.
Due to other work, I had to set aside the project until a week ago, now only the Raw data option will work!!!.

If and when I get back the FAT options I will try your code.:banghead:

I guess you know that the FAT options require a PIC with greater than 1K of free SRAM.
I use 18F2550, 18F4520 and 18F452 PIC's

Eric
 
Yeah, I'm making sure the chip can handle the code size. It seems if I am going to use a single chip solution that I'm going to have to use a different compiler. I cringe at the thought. I may just bite the bullet and use the 2 chip solution I mentioned above. I am not at work yet, so I don't know if it will do all I need, but so far it's looking good.
 
Ok, the 2 chip solution works. I have a 18F4550 grabbing data from the max6675 and sending via spi to a 18F4520 via USART. The 18F4520 stores the data on an SD Card in SPI mode and displays the data on an LCD. This is ok. Not great, but workable.

However, now a new issue is up. I apparently have to wait for all the data to be written before I can remove the SD card or the file that I am creating is blank. I have tried issuing the SDCardFAT32FileClose command, and that does in fact close the file so that the data written before the command is in the file, but then I can write no more data to the file. The program freezes if I try to reinitialze the SD Card. This tells me that I can opnly open the file once, write all the data and then close the file. After that, there is no way to apparently reopen the file for anything else. I have tried the FaileAppend command as well with no luck.

Has anyone run acros this before? Am I doing something wrong? Is there a special sequence or specific time delay that I have to have for this to work?

Any thoughts?
 
hi,
The FileAppend command is a command I have never been able to get working, I did send a bug report.

BTW I now have my FAT32 working again with a18F2550, but cannot get the UART to transmit uncorrupted data, a bug report has been sent.

Post the program code that is locking up, I will try it.

Eric
EDIT:
Try this.
Code:
Define CONFIG1L = 0x3c
Define CONFIG1H = 0x0c
Define CONFIG2L = 0x18
Define CONFIG2H = 0x00
Define CONFIG3L = 0x00
Define CONFIG3H = 0x83
Define CONFIG4L = 0x80
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40


'redo, 16Dec2015 this program works OK with 8Gb SD

'demo5b 18F2550

Define STRING_MAX_LENGTH = 16
Define CLOCK_FREQUENCY = 20

AllDigital

Dim cnt As Byte
Dim word_var As Word

Dim file_data(32) As Byte

Define LCD_LINES = 4
Define LCD_CHARS = 16
Define LCD_BITS = 4
Define LCD_DREG = PORTB
Define LCD_DBIT = 4

Define LCD_EREG = PORTB
Define LCD_EBIT = 3
Define LCD_RSREG = PORTB
Define LCD_RSBIT = 2
Define LCD_RWREG = PORTC
Define LCD_RWBIT = 0
Define LCD_READ_BUSY_FLAG = 1


Define SPI_CS_REG = PORTA
Define SPI_CS_BIT = 5
Define SPI_SCK_REG = PORTB
Define SPI_SCK_BIT = 1
Define SPI_SDI_REG = PORTB
Define SPI_SDI_BIT = 0
Define SPI_SDO_REG = PORTC
Define SPI_SDO_BIT = 7

INTCON2 = 0x00

PORTB = 0
LATB = 0
ADCON1 = 0xff
TRISB = %11110101
TRISA = 0x00

Lcdinit
Lcdout "FAT32a 17-12-15"
WaitMs 500

SDCardInit

SDCardFAT32Init
Lcdcmdout LcdClear

If sd_fat32_status.sd_fat32_error = 0 Then
Lcdout "FAT32 init OK"
Else
Lcdout "Init Fail!"
Endif

WaitMs 500

SDCardFAT32FileCreate "mydata1.txt"
Lcdcmdout LcdClear

If sd_fat32_status.sd_fat32_wr_opened = 1 Then
Lcdout "mydata1 Created"
Endif
WaitMs 500

For cnt = 1 To 100
SDCardFAT32FileWrite "17December2015", CrLf
Next cnt

Lcdcmdout LcdLine1Clear
If sd_fat32_status.sd_fat32_wr_opened = 0 Then
Lcdout "mydata1 written!"
Endif
SDCardFAT32FileClose
WaitMs 500

SDCardFAT32FileOpen "mydata1.txt"
Lcdcmdout LcdLine1Clear
If sd_fat32_status.sd_fat32_notfound = 1 Then
Lcdout "Not found!"
Endif

If sd_fat32_status.sd_fat32_opened = 1 Then
Lcdout "mydata1 found!"
WaitMs 500
Lcdcmdout LcdLine1Clear
Lcdout "filesize: ", #sd_fat32_filelen
WaitMs 500
Gosub read_file
Endif

SDCardFAT32FileClose

End                                              

read_file:
SDCardFAT32FileRead
Lcdcmdout LcdLine2Clear
Lcdout "Rd Cnt Dwn:", #sd_fat32_filelen
WaitMs 100
For cnt = 0 To 31
file_data(cnt) = sd_fat32_buff(cnt)
Next cnt
Lcdcmdout LcdLine3Clear
Lcdcmdout LcdLine4Clear

Lcdcmdout LcdLine3Home
For cnt = 0 To 15
Lcdout file_data(cnt)
Next cnt
Lcdcmdout LcdLine4Home
For cnt = 16 To 31
Lcdout file_data(cnt)
Next cnt


WaitMs 100

If sd_fat32_bytes_read = 0 Then Return
Goto read_file
Return
 
Last edited:
In PIC18F for output ports or pins you have to use LATx

Replace
Code:
Define LCD_EREG = PORTB

with

Code:
Define LCD_EREG = LATB
 
Zoiks.

Well, while this is not really a bug, it is certainly not documented and is rather inconvenient. After toying with this for a number of hours, arranging and rearranging the various commands I found that as long as all the sd card initialization commands AND all the open, write, append etc commands are in the main body, that is, not separated by a level of subroutine/function calls then everything works like it should. Very frustrating. This means there is much less modularity to my code. It works, but it's uglier than it was.... and I didn't think that was possible. I'll post my code next week so everyone can see the mess... I mean fun I've been having.

on a new note: has anyone encountered rounding errors hen using Single data type variables? I will pen a new thread for that.
 
OK. Got a reply from Vladimir. The current configuration of the SD Card commands and the SPI module precludes operation of both at the same time. In other words, you can't use the SD Card commands and then turn around and use the SPI module for other communications. That's sad. That significantly limits the functionality of the compiler as a viable alternative when faced with some of the tasks I need to perform.

That said, as promised, here's the code for the WORKING SD Card datalogger. There are 2 chips I have working together for this project. I have a 18F4550 that takes thermocouple readings and sends the data via USART to a 18F4520. The 18F4520 crunches the numbers and stores the temperatures on the SD Card using the commands. The biggest problem (aside form using SPI and the SD Card module at the same time - shame) was getting the data to write to the card and close the file so that, in the event the card were removed, the data would be viewable on the card. In other words, if the file that I am writing to is not closed in some way, when the card is read by a PC, there was no actual data on it. The reason for this has something to do with putting the SD Card write sequences in a subroutine. When the subroutine finished, there was no way to reopen the file for writing data. The fileope and fileappend commands didn't do anything. Apparently they must be preceeded by the sdcardinit and sdcardfat32init commands. Tryong to use these commands in more than 1 place in the program caused all kinds of bad behavior. The solution? I had to move all the sd card writing to the main body of the program. That way I only needed to initialize the sd card stuff once. From there, there fileappend command worked as needed.

Sorry if that was a little verbose.

Anyway, here's the code. Some of the wait periods are really long, and I don't know yet I can make them shorter. That's the next step, but in the meantime, I hope this helps someone else who may be struggling with this.
Code:
'18F4520
'internal 8MHz osc
 
'the purpose of this program is to receive data via
'USART from the slave device 18F4550, process the
'2 bytes received into a deg C value, display
'the value on the LCD and store the value on an SD Card
 
'The original version of this program works as anticipated.
'This rev will attempt to add SD Card datalogging
 
'This works as expected.
'Timer 0 is added to give timing for roughly 5 minutes.
'This will need to be changed to an RTC for the prototype
'The unit should have approximately 12 entries per hour.
'For this test there should be 13 entries:
'initial temp + 12 at roughly 5 minumte increments
 
'need to implement a write finish routine for each write cycle
'so that if the card is removed, the data is retained.
 
'This program works as expected.
 
Define CONFIG1L = 0x00
Define CONFIG1H = 0x08
Define CONFIG2L = 0x19
Define CONFIG2H = 0x00
Define CONFIG3L = 0x00
Define CONFIG3H = 0x85
Define CONFIG4L = 0x80
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40
 
'LCD Configuration - 4-bit lower
Define LCD_LINES = 2
Define LCD_CHARS = 16
Define LCD_BITS = 4
Define LCD_DREG = PORTD
Define LCD_DBIT = 4
Define LCD_RSREG = PORTD
Define LCD_RSBIT = 0
Define LCD_RWREG = PORTD
Define LCD_RWBIT = 1
Define LCD_EREG = PORTD
Define LCD_EBIT = 2
 
'SPI Configuration
Define SPI_CS_REG = PORTE
Define SPI_CS_BIT = 2
Define SPI_SCK_REG = PORTC
Define SPI_SCK_BIT = 3
Define SPI_SDI_REG = PORTC
Define SPI_SDI_BIT = 4
Define SPI_SDO_REG = PORTC
Define SPI_SDO_BIT = 5
 
Define CLOCK_FREQUENCY = 8
Define SINGLE_DECIMAL_PLACES = 2
Define SDCARD_DEFAULT_WRITE = 0x00
 
'global variables
Dim flags As Byte
Dim x As Byte  'deg symbol
Dim max_dat As Word
Dim temp As Single
Dim dat As Byte
Dim i As Word
Dim cnt As Byte
 
main:
    OSCCON = 0x72  'internal 8MHz
    Gosub setup
   
    Lcdinit 0
    Hseropen 9600
   
    Lcdout "Ready"
    WaitMs 1000
 
    Lcdcmdout LcdClear
    Lcdout "Temperature:"
 
    'initialize the sd card
    'This was originally in a subroutine, but the append command
    'would not work wihtout the initialize command comming first
    'and initializing a second time caused the program to freeze.
    '---------------------------------------------------
    SDCardInit
 
    WaitMs 1000
    Lcdcmdout LcdClear
    If sd_status.sd_error = 1 Then Lcdout "Unknown card!"
    While sd_status.sd_error = 1
    Wend
    If sd_status.sd_mmc = 1 Then Lcdout "MMC card!"
    If sd_status.sd_sd = 1 Then Lcdout "SD card!"
    If sd_status.sd_sdsc = 1 Then Lcdout "SDSC card!"
    If sd_status.sd_sdhc = 1 Then Lcdout "SDHC card!"
    WaitMs 1000
   
    SDCardFAT32Init
    Lcdcmdout LcdClear
    If sd_fat32_status.sd_fat32_error = 0 Then
        Lcdout "FAT32 initialized!"
    Else
        Lcdout "Not init."
    Endif
   
    WaitMs 2000
    SDCardFAT32FileCreate "UL248.txt"
    Lcdcmdout LcdClear
    If sd_fat32_status.sd_fat32_wr_opened = 1 Then
        Lcdout "UL248.txt created!"
    Else
        Lcdout "not created"
    Endif
    WaitMs 2000
    '--------------------------------------------------------
   
    SDCardFAT32FileWrite "TC1, TC2", CrLf
    SDCardFAT32FileClose
   
    Lcdcmdout LcdLine2Home
    x = 0xdf  'degree symbol
    'Lcdout x, "C"
    WaitMs 1000
   
   
    T0CON.7 = 1  'start tmr0
    i = 0
    flags.0 = 1  'take initial temp
    cnt = 1  'make this 1 less than the setting for the loop
loop:
    If flags.0 = 1 Then
        flags.0 = 0
        cnt = cnt + 1
        If cnt = 2 Then  '(should be set for 5 minutes)start routine: get temps, send to sd card
            cnt = 0  'reset interrupt count
           
            SDCardFAT32FileAppend "UL248.txt"  'this reopens the file for additional data
            WaitMs 1000
       
            Toggle PORTE.1
            Lcdcmdout LcdLine2Home
           
            Hserout 0x11  'send rdy
           
            'get tc1 data
            Hserin dat  'the program will wait here till a byte is received
            max_dat.HB = dat
            Hserin dat
            max_dat.LB = dat
            temp = max_dat / 4
            Lcdout "1:", #temp
            Call sd_t_out(temp)
   
            'clear possible errors
            RCSTA.FERR = 0  'framing
            RCSTA.OERR = 0  'overrun
            WaitMs 200
   
            Toggle PORTE.1
            'get tc2 data
            Hserin dat  'the program will wait here till a byte is received
            max_dat.HB = dat
            Hserin dat
            max_dat.LB = dat
            temp = max_dat / 4
            Lcdout " 2:", #temp
            Call sd_t_out(temp)
            SDCardFAT32FileWrite CrLf
            SDCardFAT32FileClose
            WaitMs 500
           
            i = i + 1
           
            If i = 500 Then  'closing will be only after themral stability
                SDCardFAT32FileClose
                Lcdcmdout LcdClear
                Lcdout "Finished"
                here: Goto here
            Endif
        Endif
    Endif
   
    Goto loop  'infinite loop
End                                              
 
 
setup:
    INTCON = 0xe0  'tmr0 int enabled
    INTCON2 = 0x84  'pull ups disabled, tmr0 int hi priority
    RCON.7 = 1  'priority ints enabled
   
    CCP1CON = 0x00  'cap / comp off
    CCP2CON = 0x00
   
    ADCON0 = 0x00  'A/D off
    ADCON1 = 0x0f  'all digital
   
    CMCON = 0x07  'comp off, digital io
    CVRCON = 0x00
       
    HLVDCON = 0x00  'Low volt detect off
   
    TRISA = 0x00
    TRISB = 0x00
    TRISC = 0x00
    TRISD = 0x00
    TRISE = 0x00
   
    LATA = 0x00
    LATB = 0x00
    LATC = 0x00
    LATD = 0x00
    LATE = 0x00
   
    'setup timer3 for interval timing
    T0CON = 0x07  'timer0 off, 1:256 prescale: approx 8.4s int
 
    flags = 0x00
Return                                           
 
 
Proc sd_t_out(dat As Single)
'dat is composed of degC in xxx.xx format
    Dim lng_num_str As String
    Dim new_cnt As Single
    Dim num_part As String
    Dim digit As String
   
    lng_num_str = #dat
    new_cnt = dat
       
        If new_cnt >= 0 And new_cnt < 10 Then
            digit = LeftStr(lng_num_str, 1)
            SDCardFAT32FileWrite digit, "."
            num_part = LeftStr(lng_num_str, 3)
            digit = RightStr(num_part, 1)
        Endif
       
        If new_cnt >= 10 And new_cnt < 100 Then
            digit = LeftStr(lng_num_str, 1)
            SDCardFAT32FileWrite digit
            num_part = LeftStr(lng_num_str, 2)
            digit = RightStr(num_part, 1)
            SDCardFAT32FileWrite digit, "."
            num_part = LeftStr(lng_num_str, 4)
            digit = RightStr(num_part, 1)
        Endif
       
        If new_cnt >= 100 Then
            digit = LeftStr(lng_num_str, 1)
            SDCardFAT32FileWrite digit
            num_part = LeftStr(lng_num_str, 2)
            digit = RightStr(num_part, 1)
            SDCardFAT32FileWrite digit
            num_part = LeftStr(lng_num_str, 3)
            digit = RightStr(num_part, 1)
            SDCardFAT32FileWrite digit, "."
            num_part = LeftStr(lng_num_str, 5)
            digit = RightStr(num_part, 1)
        Endif
        SDCardFAT32FileWrite digit, ", "
End Proc                                         
 
 
On High Interrupt
    If INTCON.2 = 1 Then  'tmr0 int
        INTCON.2 = 0
        flags.0 = 1
    Endif
Resume
 
I have a 18F4550 that takes thermocouple readings and sends the data via USART to a 18F4520. The 18F4520 crunches the numbers and stores the temperatures on the SD Card using the commands.
That seems to be the best way to achieve what you are trying to do. You could do something similar with a single Arduino, with a single PIC using a different compiler, or with a single PIC doing your own SPI/MMC library; but most of Oshonsoft's routines use bit-banged access which limits multiplexing the SPI port.
 
Hi Mity,
The Waitms times can be reduced without causing a problem, I have also used a Bit detect loop with a time out counter.
This gives an optimum response and also covers the occasions when the program fails to get the Status Bit it's testing.

The Create/Write, Append and Delete function all work OK in subr 's.

I have noticed that when I Create/Write a file and keep Appending data there are no problems, however, if use the Read command, the data is all read back OK, but I can no longer Append data, it reports 'file not found' . After a Read, the file length buffer shows zero length.!!

Have you noticed this problem.?

Eric
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top