View previous topic :: View next topic |
Author |
Message |
-Terppa-
Joined: 08 Jan 2018 Posts: 59 Location: Finland
|
RAW microSD |
Posted: Mon Aug 07, 2023 6:52 am |
|
|
Hello!
What is the simplest way to add MicroSD card to handle large amount of data?
I don't need any File Allocation Table just raw data.
That's because i can dump necessary data over uart.
What kind of drivers i need?
I'm already read part of this:
https://www.ccsinfo.com/forum/viewtopic.php?t=53787
but every line talks FATxx- systems, but i don't need them.
I have 3v3- processor so i don't need any level translators.
Thank you for pushing a right direction. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9168 Location: Greensville,Ontario
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Mon Aug 07, 2023 9:37 am |
|
|
The SD can just be added as a simple SPI device.
Key things:
Levels (already covered)
Power. The SD draws a surprising spike of power when it writes. Needs
a really good reservoir capacitor close by it's supply pins. Make sure
your supply can handle this spike.
Wiring. You need pull up resistors on CS, DATA_IN, DATA_OUT, DAT1, &
DAT2.
SDO on PIC to DATA_IN.
SDI on PIC to DATA_OUT.
SCK to SCLK
and some other suitable pin to CS.
You are looking at stuff you don't need to get involved with. As you say
those drivers are to handle FAT. The third link down at the start there is
to stuff about the MMC SD libraries. These are the only part you need.
mmc_spi.c
The only complexity with these is the speed switching. The point about
the SPI SD interface is it must start at a slow rate, negotiate how it
is going to talk to the card, and then switch up to the high speed.
The functions here handle reading a block, writing a block, etc. etc..
Just what you need. You do need to call mmc_init, since this actually
configures the SD to read/write on the SPI lines, and changes the speed. |
|
|
-Terppa-
Joined: 08 Jan 2018 Posts: 59 Location: Finland
|
|
Posted: Tue Aug 08, 2023 1:58 am |
|
|
temtronic:
Thank you for your idea! It is nice little module, but final product has very small and even that is too big.
Ttelmah:
Thank you for info!
I have now driver called "mmcsd.c" (CCSC forum)
MCU is DSpic33ep512mc204
Now it is time to start coding and wondering |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Tue Aug 08, 2023 2:22 am |
|
|
You should not need to pull any driver from the forum for this. The
mmcsd driver comes with the the compiler (drivers directory).
However you will have a slight problem. Your chip is later than this driver
was written for. So for SPI2 you need to add #pin_select statements, and
setup the spi as described here at the top of the forum (pin_select thread).
Then when the speed change has to occur, simply use the spi_speed
command instead of trying to tweak as shown in the driver.
So setup as:
Code: |
#pin_select SCK2OUT = your_pin
#pin_select SCK2IN = your_pin
#pin_select SDO2 = your_pin
#pin_select SDI2 = your_pin
#use spi(SPI2,BITS=8,MODE=0, BAUD=400000, stream=mmcsd_spi)
#define MMCSD_SPI_XFER spi_xfer(mmcsd_spi, x)
//Then load mmcsd.c
//on your chip only SPI2 uses PPS
|
For SPI1, just remove the pin_select lines, and use the hardware SPI1 pins.
Then in the mmcsd code where it changes speed:
Code: |
/// this would be a good time to set a higher clock speed, 20MHz
#if defined(MMCSD_SPI_HW)
#if (getenv("CLOCK") <= 80000000)
#define MMC_SPI_CLK_DIV SPI_CLK_DIV_4
#else
#if defined(SPI_CLK_DIV_8)
#define MMC_SPI_CLK_DIV SPI_CLK_DIV_8
#else
#define MMC_SPI_CLK_DIV SPI_CLK_DIV_16
#endif
#endif
#error/warning the next line will only work if using SPI1
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_XMIT_L_TO_H | MMC_SPI_CLK_DIV);
#endif
//Replace this with:
spi_speed(mmc_sd, 8000000);
|
Select the speed to suit what your hardware works comfortably with.
8MHz is usually fine. Some chips and with short lines will happily go
to 12MHz or more. Your chip supports 15Mbps max, but you need
well laid out short lines for this to work well.
Because you ar not using FAT, you don't have to worry about the MBR
stuff.
One comment, design however you are doing your I/O to the card to
avoid repeatedly using the same spot. So don't have the card using
something like a counter held at a fixed location at the bottom of
memory, and changing this every time you add a record. Try to think
of a way of flagging blocks as in-use with a single marker at the end
of each block. SD's are good compared to old memories in terms of
their write life, but not perfect. You still get things like SD security
cameras, killing the cards after a couple of years. |
|
|
-Terppa-
Joined: 08 Jan 2018 Posts: 59 Location: Finland
|
|
Posted: Tue Aug 08, 2023 6:14 am |
|
|
Thank you very much Mr. Ttelmah for your help!
There is something progress:
CPU: DSPic33ep512mc204 (SPI1)
SDcard adapter wiring:
(4k7 is 4.7k resistor pull-up to 3v3)
Code: |
CD:4k7
DAT1:4k7
DAT0/DO:4k7 -> (A9)
CMD/DI:4k7 -> (A4)
CLK:4k7 -> (C3)
DAT2:4k7
CAT3/CS:4k7 -> (B13)
|
CPU setup
Code: |
#define SYSTEM_CLOCK 140M
#define MYCRYSTAL 16M
#device ICSP=1
#device ADC=10
//#device PSV=16
//#build (STACK=512)
#device PASS_STRINGS=IN_RAM
//clear all RAM variables:
#ZERO_RAM
//skip list file (normally list is useless but may have handy in debug)
#nolist
//EXTERNAL clock setup DSPIC
#ifdef USEEXTERNALCLOCK
#warning CONFIRM YOUR EXTERNAL CLOCK SETUP
#fuses NOWDT //No Watch Dog Timer
#fuses CKSFSM //Clock Switching is enabled, fail Safe clock monitor is enabled
//#fuses ALTI2C1 //I2C1 mapped to ASDA1/ASCL1 pins
//#fuses ALTI2C2 //I2C2 mapped to ASDA2/ASCL2 pins
#fuses NOJTAG //JTAG disabled
#fuses PLLWAIT
#fuses CKSFSM
#fuses PR_PLL
#fuses PLLWAIT
#use delay(clock=SYSTEM_CLOCK,crystal=MYCRYSTAL)
|
SPI1 setup:
Code: |
#ifndef MMCSD_SPI_XFER
#use SPI(MASTER, SPI1, BITS=8, MSB_FIRST, MODE=0, baud=400000, stream=mmcsd_spi, FORCE_HW)
#define MMCSD_SPI_XFER(x) spi_xfer(mmcsd_spi, x)
#endif
|
There is something wrong.. Init function never get's end?
Code: |
MMCSD_err mmcsd_init()
{
unsigned int8
i,
r1;
#ifdef USEMMCSDDEBUG
fprintf(MMCSDDEBUG,"\r\n\n\rTrying to init MicroSD module..");
#endif
g_CRC_enabled = TRUE;
g_mmcsdBufferAddress = 0;
.
.
.
/* set block length to 512 bytes */
mmcsd_select();
r1 = mmcsd_set_blocklen(MMCSD_MAX_BLOCK_SIZE);
if(r1 != MMCSD_GOODEC)
{
#ifdef USEMMCSDDEBUG
fprintf(MMCSDDEBUG,"\n\rmmcsd_set_blocklen 0x%x",r1);
#endif
mmcsd_deselect();
return r1;
}
|
It returns that place and print out:
mmcsd_set_blocklen 0x80
Something missing in init? If i pull out card, it returns: mmcsd_go_idle_state |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Tue Aug 08, 2023 7:31 am |
|
|
You are not showing that you are doing the modification to the init function.
Open mmcsd.c in the IDE.
edit it as I show.
Then select 'save', and when the IDE says this is a supplied file, select
'save with project'.
Then in the project, where you open this change the include to use ""
around the filename instead of <>.
Close your project, re-open, and make sure the copy being shown in the
project is the edited version.
I suspect you are not using the edited version in the actual compile.
The original divisor change in the supplied CCS file won't work with the
SPI on your chip. |
|
|
-Terppa-
Joined: 08 Jan 2018 Posts: 59 Location: Finland
|
|
Posted: Tue Aug 08, 2023 8:48 am |
|
|
Oh, i'm sorry files in main.c
Code: |
#include "hardwareprofile.h" //CPU setup
#include "globals.h" //nothing for MicroSD
#include "mmcsd.c" //copy of CCSC forum
|
Only edited part in mmscsd.c added debug lines, SPI1- setup.
Whole init function for MicroSD:
Code: |
//________________________________________________________________________________________________________
MMCSD_err mmcsd_init()
{
unsigned int8
i,
r1;
#ifdef USEMMCSDDEBUG
fprintf(MMCSDDEBUG,"\r\n\n\rTrying to init MicroSD module..");
#endif
g_CRC_enabled = TRUE;
g_mmcsdBufferAddress = 0;
#if defined(MMCSD_PIN_SCL)
output_drive(MMCSD_PIN_SCL);
#endif
#if defined(MMCSD_PIN_SDO)
output_drive(MMCSD_PIN_SDO);
#endif
output_drive(MMCSD_PIN_SELECT);
#if defined(MMCSD_PIN_SDI)
output_float(MMCSD_PIN_SDI);
#endif
mmcsd_deselect();
delay_ms(15);
/* begin initialization */
i = 0;
do
{
delay_ms(1);
mmcsd_select();
r1=mmcsd_go_idle_state();
mmcsd_deselect();
i++;
if(i==0xff)
{
#ifdef USEMMCSDDEBUG
fprintf(MMCSDDEBUG,"\n\rmmcsd_go_idle_state");
#endif
mmcsd_deselect();
return r1;
}
} while(!bit_test(r1, 0));
i = 0;
do
{
delay_ms(1);
mmcsd_select();
r1=mmcsd_send_op_cond();
mmcsd_deselect();
i++;
if(i==0xff)
{
#ifdef USEMMCSDDEBUG
fprintf(MMCSDDEBUG,"\n\rmmcsd_send_op_cond");
#endif
mmcsd_deselect();
return r1;
}
} while(r1 & MMCSD_IDLE);
/* figure out if we have an SD or MMC */
mmcsd_select();
r1=mmcsd_app_cmd();
r1=mmcsd_sd_send_op_cond();
mmcsd_deselect();
/* an mmc will return an 0x04 here */
if(r1==0x04)
g_card_type = MMC;
else
g_card_type = SD;
/* set block length to 512 bytes */
mmcsd_select();
r1 = mmcsd_set_blocklen(MMCSD_MAX_BLOCK_SIZE);
if(r1 != MMCSD_GOODEC)
{
#ifdef USEMMCSDDEBUG
fprintf(MMCSDDEBUG,"\n\rCard type: %u",g_card_type);
fprintf(MMCSDDEBUG,"\n\rmmcsd_set_blocklen: %u/%lu, return",r1,MMCSD_MAX_BLOCK_SIZE);
#endif
mmcsd_deselect();
return r1;
}
mmcsd_deselect();
//MOD 080823
//ORIGINAL:
/*
/// this would be a good time to set a higher clock speed, 20MHz
#if defined(MMCSD_SPI_HW)
#if (getenv("CLOCK") <= 80000000)
#define MMC_SPI_CLK_DIV SPI_CLK_DIV_4
#else
#if defined(SPI_CLK_DIV_8)
#define MMC_SPI_CLK_DIV SPI_CLK_DIV_8
#else
#define MMC_SPI_CLK_DIV SPI_CLK_DIV_16
#endif
#endif
#error/warning the next line will only work if using SPI1
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_XMIT_L_TO_H | MMC_SPI_CLK_DIV);
#endif
*/
//FOR DSPIC33EP512MC204 USE
//spi_speed(mmcsd_spi, 8000000);
spi_speed(mmcsd_spi, 8000000, SYSTEMCLKSPD);
/* turn CRCs off to speed up reading/writing */
mmcsd_select();
r1 = mmcsd_crc_on_off(0);
if(r1 != MMCSD_GOODEC)
{
#ifdef USEMMCSDDEBUG
fprintf(MMCSDDEBUG,"\n\rmmcsd_crc_on_off: 0x%x",r1);
#endif
mmcsd_deselect();
return r1;
}
mmcsd_deselect();
r1 = mmcsd_load_buffer();
g_mmcsdPartitionOffset = 0;
mmcsd_check_part(0x1EE);
mmcsd_check_part(0x1DE);
mmcsd_check_part(0x1CE);
mmcsd_check_part(0x1BE);
#ifdef USEMMCSDDEBUG
fprintf(MMCSDDEBUG,"\n\rmmmcsd_load_buffer");
#endif
return r1;
}
|
It never reached end.. always returns "mmcsd_set_blocklen: 128" |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Tue Aug 08, 2023 10:07 am |
|
|
OK.
Is this a standard microSD card???
Problem is that the card is reporting that it's maximum block length is 128
bytes. The driver default is 512 bytes, which every SD card is meant to
support!....
The SD spec has the block lengths supported as 512, 1024 & 2048 bytes.
128, would only allow a maximum size of 512Kbyte.
The init is dropping out because the card is saying it can't accept the
512byte default length.
Or are you setting the block size to 128. in the load?. If so, change it
back to the default. The cards can't use a block length below 512. |
|
|
-Terppa-
Joined: 08 Jan 2018 Posts: 59 Location: Finland
|
|
Posted: Tue Aug 08, 2023 10:25 am |
|
|
It is my bad.. Accidentally i wired up MicroSD chip select to my board "heartbeat" led
It is fixed now and now i get message to terminal
"Trying to init MicroSD module..
mmcsd_send_op_cond" and return.
Without card message is same as previous:
"Trying to init MicroSD module..
mmcsd_go_idle_state
"
MicroSD card type is "Transcend, 16GB, SDHC" and circled number which says 10 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
|
-Terppa-
Joined: 08 Jan 2018 Posts: 59 Location: Finland
|
|
Posted: Tue Aug 08, 2023 12:56 pm |
|
|
Thank you very much those links! I’ll check them out. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Wed Aug 09, 2023 3:35 am |
|
|
The original power up specifications in the SD card specs say that
we need to allow 1mSec and 74 clock cycles after power on. However
a lot of the SDHC cards have their own much slower timings. For example
Sandisk specifically require 500mSec on their HC cards for this.
The driver defaults to using the SD spec timing, so a lot of the HC cards
will not respond correctly unless you lengthen this time.
A 'caveat'.... |
|
|
-Terppa-
Joined: 08 Jan 2018 Posts: 59 Location: Finland
|
|
Posted: Fri Aug 18, 2023 12:29 am |
|
|
Some progress. Now i have different types of SD card's. Brands are Transcend, Hama, Kingston and Biltema. Size are 16Gb to 32Gb.
Mr. Ttelmah suggested "dummy" data function and after digging, coding and testing i'll get this for all cards:
Code: |
Initialize SDHC..
CSD_STRUCTURE: 0
TAAC: E
NSAC: 0
TRAN_SPEED: 32
CCC: 5B5
READ_BL_LEN: 9
READ_BL_PARTIAL: 0
WRITE_BLK_MISALIGN: 0
READ_BLK_MISALIGN: 0
DSR_IMP: 0
C_SIZE: 1
VDD_R_CURR_MIN: 6
VDD_R_CURR_MAX: 3
VDD_W_CURR_MIN: 5
VDD_W_CURR_MAX: 2
C_SIZE_MULT: 2
ERASE_BLK_EN: 1
SECTOR_SIZE: 7F
WP_GRP_SIZE: 0
WP_GRP_ENABLE: 0
R2W_FACTOR: 2
WRITE_BL_LEN: 9
WRITE_BL_PARTIAL: 0
FILE_FORMAT_GRP: 0
COPY: 0
PERM_WRITE_PROTECT: 0
TMP_WRITE_PROTECT: 0
FILE_FORMAT: 0
CRC: 57
mmcsd_print_csd:0x00
Manufacturer ID: 27
OEM/Application ID: PH
OEM/Application ID: SD16G
Product Revision: 60
Serial Number: 00020
Manufacturer Date Code: 167
CRC-7 Checksum: 4F
mmcsd_print_cid:0x00
MicroSD init ready.
|
|
|
|
|