|
|
View previous topic :: View next topic |
Author |
Message |
Marco27293
Joined: 09 May 2020 Posts: 126
|
PIC18F47J53 CCS C Compiler 5.090 mmcsd.c library issue |
Posted: Fri Jul 31, 2020 9:57 am |
|
|
Hi,
I have defined a SPI on this pins in order to manage a MicroSD:
Code: | #PIN_SELECT SDO2=PIN_D2
#PIN_SELECT SDI2=PIN_D3
#PIN_SELECT SCK2=PIN_D4
#define MMCSD_PIN_SCK PIN_D4 //o
#define MMCSD_PIN_MISO PIN_D3 //i
#define MMCSD_PIN_MOSI PIN_D2 //o
#define MMCSD_PIN_SELECT PIN_D0 //o
#ifndef MMCSD_SPI_HW
#use spi(MASTER,SPI2, DI=MMCSD_PIN_MISO, DO=MMCSD_PIN_MOSI, CLK=MMCSD_PIN_SCK, BITS=8, MSB_FIRST, MODE=3, baud=400000)
#endif
|
I configure ports this way:
Code: |
void config_port()
{
LATE = 0b00000000;
PORTE = 0b00000000;
LATD = 0b00001000;
PORTD = 0b00001000;
LATC = 0b00000000;
PORTC = 0b00000000;
LATB = 0b00001000;
PORTB = 0b00001000;
LATA = 0b00000000;
PORTA = 0b00000000;
set_tris_a(0b00100110);
set_tris_b(0b11111011);
set_tris_c(0b11111111);
INTCON2 = 0b10000000;
}
|
When I go to DeepSleep I set :
Code: |
output_low(PIN_D2); //MOSI
output_low(PIN_D3); //MISO
output_low(PIN_D4); //SCK
output_low(PIN_D0); //CS
|
But PIN_D4 during deepsleep remains high (3.3 V) and the MicroSD consumes about 2mA... Why??
Please I need help for an important project.
Regards,
Marco |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Fri Jul 31, 2020 10:08 am |
|
|
Because in Mode3, the SPI idles high. The pin is under the control of the
SPI peripheral, and not available for normal I/O.
The clock being high should not cause the card to consume extra current.
This depends on how the card is initialised. You can program an SD to
automatically sleep when the clock stops. However don't know how the
default SD library sets things up. |
|
|
Marco27293
Joined: 09 May 2020 Posts: 126
|
|
Posted: Fri Jul 31, 2020 10:13 am |
|
|
Code: |
/////////////////////////////////////////////////////////////////////////
//// mmcsd_m.c ////
//// ////
//// This driver is a modified version of CCS C compiler mmcsd.c ////
//// file, now it supports all types of cards: MMC, SD and SDHC. ////
//// ////
//// https://simple-circuit.com/ ////
//// contact@simple-circuit.com ////
//// ////
/////////////////////////////////////////////////////////////////////////
//// ////
//// This is a low-level driver for MMC and SD cards. ////
//// ////
//// --User Functions-- ////
//// ////
//// mmcsd_init(): Initializes the media. ////
//// ////
//// mmcsd_read_byte(a, p) ////
//// Reads a byte from the MMC/SD card at location a, saves to ////
//// pointer p. Returns 0 if OK, non-zero if error. ////
//// ////
//// mmcsd_read_data(a, n, p) ////
//// Reads n bytes of data from the MMC/SD card starting at address ////
//// a, saves result to pointer p. Returns 0 if OK, non-zero if ////
//// error. ////
//// ////
//// mmcsd_flush_buffer() ////
//// The two user write functions (mmcsd_write_byte() and ////
//// mmcsd_write_data()) maintain a buffer to speed up the writing ////
//// process. Whenever a read or write is performed, the write ////
//// buffer is loaded with the specified page and only the ////
//// contents of this buffer is changed. If any future writes ////
//// cross a page boundary then the buffer in RAM is written ////
//// to the MMC/SD and then the next page is loaded into the ////
//// buffer. mmcsd_flush_buffer() forces the contents in RAM ////
//// to the MMC/SD card. Returns 0 if OK, non-zero if errror. ////
//// ////
//// mmcsd_write_byte(a, d) ////
//// Writes data byte d to the MMC/SD address a. Intelligently ////
//// manages a write buffer, therefore you may need to call ////
//// mmcsd_flush_buffer() to flush the buffer. ////
//// ////
//// mmcsd_write_data(a, n, p) ////
//// Writes n bytes of data from pointer p to the MMC/SD card ////
//// starting at address a. This function intelligently manages ////
//// a write buffer, therefore if you may need to call ////
//// mmcsd_flush_buffer() to flush any buffered characters. ////
//// returns 0 if OK, non-zero if error. ////
//// ////
//// mmcsd_read_block(a, s, p) ////
//// Reads an entire page from the SD/MMC. Keep in mind that the ////
//// start of the read has to be aligned to a block ////
//// (Address % 512 = 0). Therefore s must be evenly divisible by ////
//// 512. At the application level it is much more effecient to ////
//// to use mmcsd_read_data() or mmcsd_read_byte(). Returns 0 ////
//// if successful, non-zero if error. ////
//// ////
//// mmcsd_write_block(a, s, p): ////
//// Writes an entire page to the SD/MMC. This will write an ////
//// entire page to the SD/MMC, so the address and size must be ////
//// evenly divisble by 512. At the application level it is much ////
//// more effecient to use mmcsd_write_data() or mmcsd_write_byte().////
//// Returns 0 if successful, non-zero if error. ////
//// ////
//// mmcsd_print_cid(): Displays all data in the Card Identification ////
//// Register. Note this only works on SD cards. ////
//// ////
//// mmcsd_print_csd(): Displays all data in the Card Specific Data ////
//// Register. Note this only works on SD cards. ////
//// ////
//// ////
//// --Non-User Functions-- ////
//// ////
//// mmcsd_go_idle_state(): Sends the GO_IDLE_STATE command to the ////
//// SD/MMC. ////
//// mmcsd_send_op_cond(): Sends the SEND_OP_COND command to the ////
//// SD. Note this command only works on SD. ////
//// mmcsd_send_if_cond(): Sends the SEND_IF_COND command to the ////
//// SD. Note this command only works on SD. ////
//// mmcsd_sd_status(): Sends the SD_STATUS command to the SD. Note ////
//// This command only works on SD cards. ////
//// mmcsd_send_status(): Sends the SEND_STATUS command to the ////
//// SD/MMC. ////
//// mmcsd_set_blocklen(): Sends the SET_BLOCKLEN command along with ////
//// the desired block length. ////
//// mmcsd_app_cmd(): Sends the APP_CMD command to the SD. This only ////
//// works on SD cards and is used just before any ////
//// SD-only command (e.g. send_op_cond()). ////
//// mmcsd_read_ocr(): Sends the READ_OCR command to the SD/MMC. ////
//// mmcsd_crc_on_off(): Sends the CRC_ON_OFF command to the SD/MMC ////
//// along with a bit to turn the CRC on/off. ////
//// mmcsd_send_cmd(): Sends a command and argument to the SD/MMC. ////
//// mmcsd_get_r1(): Waits for an R1 response from the SD/MMC and ////
//// then saves the response to a buffer. ////
//// mmcsd_get_r2(): Waits for an R2 response from the SD/MMC and ////
//// then saves the response to a buffer. ////
//// mmcsd_get_r3(): Waits for an R3 response from the SD/MMC and ////
//// then saves the response to a buffer. ////
//// mmcsd_get_r7(): Waits for an R7 response from the SD/MMC and ////
//// then saves the response to a buffer. ////
//// mmcsd_wait_for_token(): Waits for a specified token from the ////
//// SD/MMC. ////
//// mmcsd_crc7(): Generates a CRC7 using a pointer to some data, ////
//// and how many bytes long the data is. ////
//// mmcsd_crc16(): Generates a CRC16 using a pointer to some data, ////
//// and how many bytes long the data is. ////
//// ////
/////////////////////////////////////////////////////////////////////////
//// (C) Copyright 2007 Custom Computer Services ////
//// This source code may only be used by licensed users of the CCS ////
//// C compiler. This source code may only be distributed to other ////
//// licensed users of the CCS C compiler. No other use, ////
//// reproduction or distribution is permitted without written ////
//// permission. Derivative programs created using this software ////
//// in object code form are not restricted in any way. ////
/////////////////////////////////////////////////////////////////////////
#ifndef MMCSD_C
#define MMCSD_C
/////////////////////
//// ////
//// User Config ////
//// ////
/////////////////////
#include <stdint.h>
#PIN_SELECT SDO2=PIN_D2
#PIN_SELECT SDI2=PIN_D3
#PIN_SELECT SCK2=PIN_D4
#define MMCSD_PIN_SCK PIN_D4 //o
#define MMCSD_PIN_MISO PIN_D3 //i
#define MMCSD_PIN_MOSI PIN_D2 //o
#define MMCSD_PIN_SELECT PIN_D0 //o
#ifndef MMCSD_SPI_HW
#use spi(MASTER,SPI2, DI=MMCSD_PIN_MISO, DO=MMCSD_PIN_MOSI, CLK=MMCSD_PIN_SCK, BITS=8, MSB_FIRST, MODE=3, baud=400000)
#endif
////////////////////////
//// ////
//// Useful Defines ////
//// ////
////////////////////////
enum MMCSD_err
{MMCSD_GOODEC = 0,
MMCSD_IDLE = 0x01,
MMCSD_ERASE_RESET = 0x02,
MMCSD_ILLEGAL_CMD = 0x04,
MMCSD_CRC_ERR = 0x08,
MMCSD_ERASE_SEQ_ERR = 0x10,
MMCSD_ADDR_ERR = 0x20,
MMCSD_PARAM_ERR = 0x40,
RESP_TIMEOUT = 0x80};
#define GO_IDLE_STATE 0
#define SEND_OP_COND 1
#define SEND_IF_COND 8
#define SEND_CSD 9
#define SEND_CID 10
#define SD_STATUS 13
#define SEND_STATUS 13
#define SET_BLOCKLEN 16
#define READ_SINGLE_BLOCK 17
#define WRITE_BLOCK 24
#define SD_SEND_OP_COND 41
#define APP_CMD 55
#define READ_OCR 58
#define CRC_ON_OFF 59
#define IDLE_TOKEN 0x01
#define DATA_START_TOKEN 0xFE
#define MMCSD_MAX_BLOCK_SIZE 512
////////////////////////
/// ///
/// Global Variables ///
/// ///
////////////////////////
uint8_t g_mmcsd_buffer[MMCSD_MAX_BLOCK_SIZE];
int1 g_CRC_enabled;
int1 g_MMCSDBufferChanged;
uint32_t g_mmcsdBufferAddress;
enum _card_type{MMC, SDSC, SDHC} g_card_type;
/////////////////////////////
//// ////
//// Function Prototypes ////
//// ////
/////////////////////////////
MMCSD_err mmcsd_init();
MMCSD_err mmcsd_read_data(uint32_t address, uint16_t size, uint8_t* ptr);
MMCSD_err mmcsd_read_block(uint32_t address, uint16_t size, uint8_t* ptr);
MMCSD_err mmcsd_write_data(uint32_t address, uint16_t size, uint8_t* ptr);
MMCSD_err mmcsd_write_block(uint32_t address, uint16_t size, uint8_t* ptr);
MMCSD_err mmcsd_go_idle_state(void);
MMCSD_err mmcsd_send_op_cond(void);
MMCSD_err mmcsd_send_if_cond(uint8_t r7[]);
MMCSD_err mmcsd_print_csd();
MMCSD_err mmcsd_print_cid();
MMCSD_err mmcsd_sd_status(uint8_t r2[]);
MMCSD_err mmcsd_send_status(uint8_t r2[]);
MMCSD_err mmcsd_set_blocklen(uint32_t blocklen);
MMCSD_err mmcsd_read_single_block(uint32_t address);
MMCSD_err mmcsd_write_single_block(uint32_t address);
MMCSD_err mmcsd_sd_send_op_cond(void);
MMCSD_err mmcsd_app_cmd(void);
MMCSD_err mmcsd_read_ocr(uint8_t* r1);
MMCSD_err mmcsd_crc_on_off(int1 crc_enabled);
MMCSD_err mmcsd_send_cmd(uint8_t cmd, uint32_t arg);
MMCSD_err mmcsd_get_r1(void);
MMCSD_err mmcsd_get_r2(uint8_t r2[]);
MMCSD_err mmcsd_get_r3(uint8_t r3[]);
MMCSD_err mmcsd_get_r7(uint8_t r7[]);
MMCSD_err mmcsd_wait_for_token(uint8_t token);
uint8_t mmcsd_crc7(char *data, uint8_t length);
//uint16_t mmcsd_crc16(char *data, uint8_t length); // Not needed --> commented
void mmcsd_select();
void mmcsd_deselect();
/// Fast Functions ! ///
MMCSD_err mmcsd_load_buffer(void);
MMCSD_err mmcsd_flush_buffer(void);
MMCSD_err mmcsd_move_buffer(uint32_t new_addr);
MMCSD_err mmcsd_read_byte(uint32_t addr, char* data);
MMCSD_err mmcsd_write_byte(uint32_t addr, char data);
//////////////////////////////////
//// ////
//// Function Implementations ////
//// ////
//////////////////////////////////
int8 MMCSD_SPI_XFER(int8 spi_data) {
#ifdef MMCSD_SPI_HW
return SPI_Read(spi_data);
#else
return spi_xfer(spi_data);
#endif
}
MMCSD_err mmcsd_init()
{
uint8_t
i,
r1,
r3[4];
g_CRC_enabled = TRUE;
g_mmcsdBufferAddress = 0;
output_drive(MMCSD_PIN_SELECT);
#ifdef MMCSD_SPI_HW
SETUP_SPI(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_64 | SPI_XMIT_L_TO_H);
#else // Software SPI
output_drive(MMCSD_PIN_SCK);
output_drive(MMCSD_PIN_MOSI);
output_float(MMCSD_PIN_MISO);
#endif
mmcsd_deselect();
delay_ms(250);
for(i = 0; i < 10; i++) // Send 80 cycles
MMCSD_SPI_XFER(0xFF);
/* begin initialization */
i = 0;
do
{
delay_ms(1);
mmcsd_select();
r1 = mmcsd_go_idle_state();
mmcsd_deselect();
i++;
if(i == 0xFF) {
if (r1 == 0)
return 1;
else
return r1;
}
} while(r1 != MMCSD_IDLE);
i = 0;
do
{
delay_ms(1);
mmcsd_select();
r1 = mmcsd_send_op_cond();
mmcsd_deselect();
i++;
} while((r1 & MMCSD_IDLE) && i != 0xFF);
if(i == 0xFF) {
delay_ms(100);
mmcsd_select();
r1 = mmcsd_go_idle_state();
mmcsd_deselect();
delay_ms(100);
mmcsd_select();
r1 = mmcsd_send_if_cond(r3);
mmcsd_deselect();
if(r1 != MMCSD_IDLE)
return r1;
}
/* figure out if we have an SD or MMC */
i = 0;
do {
mmcsd_select();
r1=mmcsd_app_cmd();
r1=mmcsd_sd_send_op_cond();
mmcsd_deselect();
delay_ms(100);
i++;
} while((r1 == MMCSD_IDLE) && (i != 0xFF));
if(r1 == MMCSD_IDLE)
return r1;
/* an mmc will return an 0x04 here */
if(r1 == 0x04)
g_card_type = MMC;
else {
g_card_type = SDSC;
mmcsd_select();
r1 = mmcsd_read_ocr(r3);
mmcsd_deselect();
if(r1 != MMCSD_ILLEGAL_CMD) {
r1 = r3[3];
if(bit_test(r1, 6)) // If bit 30 of the OCR register is 1 (CCS is 1) ==> SDHC type
g_card_type = SDHC;
}
}
/* set block length to 512 bytes */
mmcsd_select();
r1 = mmcsd_set_blocklen(MMCSD_MAX_BLOCK_SIZE);
mmcsd_deselect();
if(r1 != MMCSD_GOODEC)
return r1;
/// this would be a good time to set a higher clock speed, 20MHz
#ifdef MMCSD_SPI_HW
setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_XMIT_L_TO_H | SPI_CLK_DIV_4);
#else
#use spi(MASTER, DI=MMCSD_PIN_MISO, DO=MMCSD_PIN_MOSI, CLK=MMCSD_PIN_SCK, BITS=8, MODE=3)
#endif
// Turn OFF CRC check, some card return 0 (MMCSD_GOODEC) and some others return 0x04 (MMCSD_ILLEGAL_CMD)
mmcsd_select();
r1 = mmcsd_crc_on_off(FALSE);
mmcsd_deselect();
r1 = mmcsd_load_buffer();
return MMCSD_GOODEC;
}
MMCSD_err mmcsd_read_data(uint32_t address, uint16_t size, uint8_t* ptr)
{
MMCSD_err r1;
uint16_t i; // counter for loops
for(i = 0; i < size; i++)
{
r1 = mmcsd_read_byte(address++, ptr++);
if(r1 != MMCSD_GOODEC)
return r1;
}
return MMCSD_GOODEC;
}
MMCSD_err mmcsd_read_block(uint32_t address, uint16_t size, uint8_t* ptr)
{
MMCSD_err ec;
uint16_t i; // counter for loops
// send command
mmcsd_select();
ec = mmcsd_read_single_block(address);
if(ec != MMCSD_GOODEC)
{
mmcsd_deselect();
return ec;
}
// wait for the data start token
ec = mmcsd_wait_for_token(DATA_START_TOKEN);
if(ec != MMCSD_GOODEC)
{
mmcsd_deselect();
return ec;
}
// read in the data
for(i = 0; i < size; i += 1)
ptr[i] = MMCSD_SPI_XFER(0xFF);
/* if(g_CRC_enabled) // already FALSE
{
// check the crc
if(make16(MMCSD_SPI_XFER(0xFF), MMCSD_SPI_XFER(0xFF)) != mmcsd_crc16(g_mmcsd_buffer, MMCSD_MAX_BLOCK_SIZE))
{
mmcsd_deselect();
return MMCSD_CRC_ERR;
}
}
else
{ */
/* have the card transmit the CRC, but ignore it */
MMCSD_SPI_XFER(0xFF);
MMCSD_SPI_XFER(0xFF);
// }
mmcsd_deselect();
return MMCSD_GOODEC;
}
MMCSD_err mmcsd_write_data(uint32_t address, uint16_t size, uint8_t* ptr)
{
MMCSD_err ec;
uint16_t i; // counter for loops
for(i = 0; i < size; i++)
{
ec = mmcsd_write_byte(address++, *ptr++);
if(ec != MMCSD_GOODEC)
return ec;
}
return MMCSD_GOODEC;
}
MMCSD_err mmcsd_write_block(uint32_t address, uint16_t size, uint8_t* ptr)
{
MMCSD_err ec;
uint16_t i;
// send command
mmcsd_select();
ec = mmcsd_write_single_block(address);
if(ec != MMCSD_GOODEC)
{
mmcsd_deselect();
return ec;
}
// send a data start token
MMCSD_SPI_XFER(DATA_START_TOKEN);
// send all the data
for(i = 0; i < size; i += 1)
{
MMCSD_SPI_XFER(ptr[i]);
}
// if the CRC is enabled we have to calculate it, otherwise just send an 0xFFFF
/* if(g_CRC_enabled) // already FALSE
MMCSD_SPI_XFER(mmcsd_crc16(ptr, size));
else
{ */
MMCSD_SPI_XFER(0xFF);
MMCSD_SPI_XFER(0xFF);
// }
// get the error code back from the card; "data accepted" is 0bXXX00101
ec = mmcsd_get_r1();
if(ec & 0x0A)
{
mmcsd_deselect();
return ec;
}
// wait for the line to go back high, this indicates that the write is complete
while(MMCSD_SPI_XFER(0xFF) == 0);
mmcsd_deselect();
return MMCSD_GOODEC;
}
MMCSD_err mmcsd_go_idle_state(void)
{
mmcsd_send_cmd(GO_IDLE_STATE, 0);
return mmcsd_get_r1();
}
MMCSD_err mmcsd_send_op_cond(void)
{
mmcsd_send_cmd(SEND_OP_COND, 0);
return mmcsd_get_r1();
}
MMCSD_err mmcsd_send_if_cond(uint8_t r7[])
{
mmcsd_send_cmd(SEND_IF_COND, 0x1AA);
return mmcsd_get_r7(r7);
}
MMCSD_err mmcsd_print_csd()
{
uint8_t
buf[16],
i,
r1;
// MMCs don't support this command
if(g_card_type == MMC)
return MMCSD_PARAM_ERR;
mmcsd_select();
mmcsd_send_cmd(SEND_CSD, 0);
r1 = mmcsd_get_r1();
if(r1 != MMCSD_GOODEC)
{
mmcsd_deselect();
return r1;
}
r1 = mmcsd_wait_for_token(DATA_START_TOKEN);
if(r1 != MMCSD_GOODEC)
{
mmcsd_deselect();
return r1;
}
for(i = 0; i < 16; i++)
buf[i] = MMCSD_SPI_XFER(0xFF);
mmcsd_deselect();
/*
printf("\r\nCSD_STRUCTURE: %X", (buf[0] & 0x0C) >> 2);
printf("\r\nTAAC: %X", buf[1]);
printf("\r\nNSAC: %X", buf[2]);
printf("\r\nTRAN_SPEED: %X", buf[3]);
printf("\r\nCCC: %lX", (make16(buf[4], buf[5]) & 0xFFF0) >> 4);
printf("\r\nREAD_BL_LEN: %X", buf[5] & 0x0F);
printf("\r\nREAD_BL_PARTIAL: %X", (buf[6] & 0x80) >> 7);
printf("\r\nWRITE_BLK_MISALIGN: %X", (buf[6] & 0x40) >> 6);
printf("\r\nREAD_BLK_MISALIGN: %X", (buf[6] & 0x20) >> 5);
printf("\r\nDSR_IMP: %X", (buf[6] & 0x10) >> 4);
printf("\r\nC_SIZE: %lX", (((buf[6] & 0x03) << 10) | (buf[7] << 2) | ((buf[8] & 0xC0) >> 6)));
printf("\r\nVDD_R_CURR_MIN: %X", (buf[8] & 0x38) >> 3);
printf("\r\nVDD_R_CURR_MAX: %X", buf[8] & 0x07);
printf("\r\nVDD_W_CURR_MIN: %X", (buf[9] & 0xE0) >> 5);
printf("\r\nVDD_W_CURR_MAX: %X", (buf[9] & 0x1C) >> 2);
printf("\r\nC_SIZE_MULT: %X", ((buf[9] & 0x03) << 1) | ((buf[10] & 0x80) >> 7));
printf("\r\nERASE_BLK_EN: %X", (buf[10] & 0x40) >> 6);
printf("\r\nSECTOR_SIZE: %X", ((buf[10] & 0x3F) << 1) | ((buf[11] & 0x80) >> 7));
printf("\r\nWP_GRP_SIZE: %X", buf[11] & 0x7F);
printf("\r\nWP_GRP_ENABLE: %X", (buf[12] & 0x80) >> 7);
printf("\r\nR2W_FACTOR: %X", (buf[12] & 0x1C) >> 2);
printf("\r\nWRITE_BL_LEN: %X", ((buf[12] & 0x03) << 2) | ((buf[13] & 0xC0) >> 6));
printf("\r\nWRITE_BL_PARTIAL: %X", (buf[13] & 0x20) >> 5);
printf("\r\nFILE_FORMAT_GRP: %X", (buf[14] & 0x80) >> 7);
printf("\r\nCOPY: %X", (buf[14] & 0x40) >> 6);
printf("\r\nPERM_WRITE_PROTECT: %X", (buf[14] & 0x20) >> 5);
printf("\r\nTMP_WRITE_PROTECT: %X", (buf[14] & 0x10) >> 4);
printf("\r\nFILE_FORMAT: %X", (buf[14] & 0x0C) >> 2);
printf("\r\nCRC: %X", buf[15]);
*/
return r1;
}
MMCSD_err mmcsd_print_cid()
{
uint8_t
buf[16],
i,
r1;
// MMCs don't support this command
if(g_card_type == MMC)
return MMCSD_PARAM_ERR;
mmcsd_select();
mmcsd_send_cmd(SEND_CID, 0);
r1 = mmcsd_get_r1();
if(r1 != MMCSD_GOODEC)
{
mmcsd_deselect();
return r1;
}
r1 = mmcsd_wait_for_token(DATA_START_TOKEN);
if(r1 != MMCSD_GOODEC)
{
mmcsd_deselect();
return r1;
}
for(i = 0; i < 16; i++)
buf[i] = MMCSD_SPI_XFER(0xFF);
mmcsd_deselect();
/*
printf("\r\nManufacturer ID: %X", buf[0]);
printf("\r\nOEM/Application ID: %c%c", buf[1], buf[2]);
printf("\r\nOEM/Application ID: %c%c%c%c%c", buf[3], buf[4], buf[5], buf[6], buf[7]);
printf("\r\nProduct Revision: %X", buf[8]);
printf("\r\nSerial Number: %X%X%X%X", buf[9], buf[10], buf[11], buf[12]);
printf("\r\nManufacturer Date Code: %X%X", buf[13] & 0x0F, buf[14]);
printf("\r\nCRC-7 Checksum: %X", buf[15]);
*/
return r1;
}
MMCSD_err mmcsd_sd_status(uint8_t r2[])
{
uint8_t i;
mmcsd_select();
mmcsd_send_cmd(APP_CMD, 0);
r2[0]=mmcsd_get_r1();
mmcsd_deselect();
mmcsd_select();
mmcsd_send_cmd(SD_STATUS, 0);
for(i = 0; i < 64; i++)
MMCSD_SPI_XFER(0xFF);
mmcsd_deselect();
return mmcsd_get_r2(r2);
}
MMCSD_err mmcsd_send_status(uint8_t r2[])
{
mmcsd_send_cmd(SEND_STATUS, 0);
return mmcsd_get_r2(r2);
}
MMCSD_err mmcsd_set_blocklen(uint32_t blocklen)
{
mmcsd_send_cmd(SET_BLOCKLEN, blocklen);
return mmcsd_get_r1();
}
MMCSD_err mmcsd_read_single_block(uint32_t address)
{
mmcsd_send_cmd(READ_SINGLE_BLOCK, address);
return mmcsd_get_r1();
}
MMCSD_err mmcsd_write_single_block(uint32_t address)
{
mmcsd_send_cmd(WRITE_BLOCK, address);
return mmcsd_get_r1();
}
MMCSD_err mmcsd_sd_send_op_cond(void)
{
mmcsd_send_cmd(SD_SEND_OP_COND, 0x40000000);
return mmcsd_get_r1();
}
MMCSD_err mmcsd_app_cmd(void)
{
mmcsd_send_cmd(APP_CMD, 0);
return mmcsd_get_r1();
}
MMCSD_err mmcsd_read_ocr(int r3[])
{
mmcsd_send_cmd(READ_OCR, 0);
return mmcsd_get_r3(r3);
}
MMCSD_err mmcsd_crc_on_off(int1 crc_enabled)
{
mmcsd_send_cmd(CRC_ON_OFF, crc_enabled);
g_CRC_enabled = crc_enabled;
return mmcsd_get_r1();
}
MMCSD_err mmcsd_send_cmd(uint8_t cmd, uint32_t arg)
{
uint8_t packet[6]; // the entire command, argument, and crc in one variable
// construct the packet
// every command on an SD card is or'ed with 0x40
packet[0] = cmd | 0x40;
packet[1] = make8(arg, 3);
packet[2] = make8(arg, 2);
packet[3] = make8(arg, 1);
packet[4] = make8(arg, 0);
// calculate the crc if needed
if(g_CRC_enabled)
packet[5] = mmcsd_crc7(packet, 5);
else
packet[5] = 0xFF;
// transfer the command and argument, with an extra 0xFF hacked in there
MMCSD_SPI_XFER(packet[0]);
MMCSD_SPI_XFER(packet[1]);
MMCSD_SPI_XFER(packet[2]);
MMCSD_SPI_XFER(packet[3]);
MMCSD_SPI_XFER(packet[4]);
MMCSD_SPI_XFER(packet[5]);
//! spi_write2(packet[0]);
//! spi_write2(packet[1]);
//! spi_write2(packet[2]);
//! spi_write2(packet[3]);
//! spi_write2(packet[4]);
//! spi_write2(packet[5]);
return MMCSD_GOODEC;
}
MMCSD_err mmcsd_get_r1(void)
{
uint8_t
response = 0, // place to hold the response coming back from the SPI line
timeout = 0xFF; // maximum amount loops to wait for idle before getting impatient and leaving the function with an error code
// loop until timeout == 0
while(timeout)
{
// read what's on the SPI line
// the SD/MMC requires that you leave the line high when you're waiting for data from it
response = MMCSD_SPI_XFER(0xFF);
//response = MMCSD_SPI_XFER(0x00);//leave the line idle
// check to see if we got a response
if(response != 0xFF)
{
// fill in the response that we got and leave the function
return response;
}
// wait for a little bit longer
timeout--;
}
// for some reason, we didn't get a response back from the card
// return the proper error codes
return RESP_TIMEOUT;
}
MMCSD_err mmcsd_get_r2(uint8_t r2[])
{
r2[1] = mmcsd_get_r1();
r2[0] = MMCSD_SPI_XFER(0xFF);
return 0;
}
MMCSD_err mmcsd_get_r3(uint8_t r3[])
{
return mmcsd_get_r7(r3);
}
MMCSD_err mmcsd_get_r7(uint8_t r7[])
{
uint8_t i; // counter for loop
// the top byte of r7 is r1
r7[4]=mmcsd_get_r1();
// fill in the other 4 bytes
for(i = 0; i < 4; i++)
r7[3 - i] = MMCSD_SPI_XFER(0xFF);
return r7[4];
}
MMCSD_err mmcsd_wait_for_token(uint8_t token)
{
MMCSD_err r1;
// get a token
r1 = mmcsd_get_r1();
// check to see if the token we recieved was the one that we were looking for
if(r1 == token)
return MMCSD_GOODEC;
// if that wasn't right, return the error
return r1;
}
unsigned int8 mmcsd_crc7(char *data,uint8_t length)
{
uint8_t i, ibit, c, crc;
crc = 0x00; // Set initial value
for (i = 0; i < length; i++, data++)
{
c = *data;
for (ibit = 0; ibit < 8; ibit++)
{
crc = crc << 1;
if ((c ^ crc) & 0x80) crc = crc ^ 0x09; // ^ is XOR
c = c << 1;
}
crc = crc & 0x7F;
}
shift_left(&crc, 1, 1); // MMC card stores the result in the top 7 bits so shift them left 1
// Should shift in a 1 not a 0 as one of the cards I have won't work otherwise
return crc;
}
/* Not needed function (CRC is OFF)
uint16_t mmcsd_crc16(char *data, uint8_t length)
{
uint8_t i, ibit, c;
uint16_t crc;
crc = 0x0000; // Set initial value
for (i = 0; i < length; i++, data++)
{
c = *data;
for (ibit = 0; ibit < 8; ibit++)
{
crc = crc << 1;
if ((c ^ crc) & 0x8000) crc = crc ^ 0x1021; // ^ is XOR
c = c << 1;
}
crc = crc & 0x7FFF;
}
shift_left(&crc, 2, 1); // MMC card stores the result in the top 7 bits so shift them left 1
// Should shift in a 1 not a 0 as one of the cards I have won't work otherwise
return crc;
}
*/
void mmcsd_select()
{
output_low(MMCSD_PIN_SELECT);
}
void mmcsd_deselect()
{
//MMCSD_SPI_XFER(0xFF);
output_high(MMCSD_PIN_SELECT);
}
MMCSD_err mmcsd_load_buffer(void)
{
g_MMCSDBufferChanged = FALSE;
return(mmcsd_read_block(g_mmcsdBufferAddress, MMCSD_MAX_BLOCK_SIZE, g_mmcsd_buffer));
}
MMCSD_err mmcsd_flush_buffer(void)
{
if (g_MMCSDBufferChanged)
{
g_MMCSDBufferChanged = FALSE;
return(mmcsd_write_block(g_mmcsdBufferAddress, MMCSD_MAX_BLOCK_SIZE, g_mmcsd_buffer));
}
return(0); //ok
}
MMCSD_err mmcsd_move_buffer(uint32_t new_addr)
{
MMCSD_err ec = MMCSD_GOODEC;
uint32_t
//cur_block,
new_block;
// make sure we're still on the same block
//cur_block = g_mmcsdBufferAddress - (g_mmcsdBufferAddress % MMCSD_MAX_BLOCK_SIZE);
if(g_card_type == SDHC)
new_block = new_addr / MMCSD_MAX_BLOCK_SIZE;
else
new_block = new_addr - (new_addr % MMCSD_MAX_BLOCK_SIZE);
//if(cur_block != new_block)
if(g_mmcsdBufferAddress != new_block)
{
// dump the old buffer
if (g_MMCSDBufferChanged)
{
ec = mmcsd_flush_buffer();
if(ec != MMCSD_GOODEC)
return ec;
g_MMCSDBufferChanged = FALSE;
}
// figure out the best place for a block
g_mmcsdBufferAddress = new_block;
// load up a new buffer
ec = mmcsd_load_buffer();
}
return ec;
}
MMCSD_err mmcsd_read_byte(uint32_t addr, char* data)
{
MMCSD_err ec;
ec = mmcsd_move_buffer(addr);
if(ec != MMCSD_GOODEC)
{
return ec;
}
*data = g_mmcsd_buffer[addr % MMCSD_MAX_BLOCK_SIZE];
return MMCSD_GOODEC;
}
MMCSD_err mmcsd_write_byte(uint32_t addr, char data)
{
MMCSD_err ec;
ec = mmcsd_move_buffer(addr);
if(ec != MMCSD_GOODEC)
return ec;
g_mmcsd_buffer[addr % MMCSD_MAX_BLOCK_SIZE] = data;
g_MMCSDBufferChanged = TRUE;
return MMCSD_GOODEC;
}
#endif
|
This is my driver how can I modify it in order to NOT consume extra current? |
|
|
Marco27293
Joined: 09 May 2020 Posts: 126
|
|
Posted: Fri Jul 31, 2020 11:29 am |
|
|
An additional information: When the PIC goes to deep sleep, the MicroSD supply provided by a 3.3V LDO voltage regulator is switched off.
So I think that MicroSD consumes 2mA through SCK, it is the ONLY MicroSD pin high (3.3V), I checked with a multimeter....
Otherwise how might MicroSD consume this current ?
Is my deduction correct? If yes, how can I set spi in order to have SCK pin low?
Is it sufficient to change MODE parameter in #use spi setting ?
Thank you,
Marco |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Fri Jul 31, 2020 12:59 pm |
|
|
OK.
Powering off the SD is a different kettle of fish.
In this case, the trick is to take advantage of pin_select (the 'in code'
version of this operation), to deselect the pin.
So:
Code: |
pin_select(NULL,PIN_D4);
output_low(PIN_D2); //MOSI
output_low(PIN_D3); //MISO
output_low(PIN_D4); //SCK
output_low(PIN_D0); //CS
//Then when you wake up, re-select the pin:
pin_select(SCLK2,PIN_D4); //before using the SPI
|
Remember your fuses must be set to allow the selections to be changed
more than once. |
|
|
Marco27293
Joined: 09 May 2020 Posts: 126
|
|
Posted: Mon Aug 03, 2020 7:34 am |
|
|
Thank you Ttelmah,
This directive belongs to a library included by main at each wake-up:
#PIN_SELECT SCK2=PIN_D4
Is it sufficient or Have I to add in code pin_select(SCLK2, PIN_D4); ??
These are my current fuses:
Code: |
#FUSES RTCOSC_INT // Real Time Clock-Calendar enabled and uses internal clock
#FUSES WDT,WDT1024 // Watch Dog Timer enabled and uses internal clock with 1:1024 Postscale (4.1 sec)
#FUSES DSWDT,DSWDTOSC_INT // Deep Sleep Watch Dog Timer enabled and uses internal clock with 1:33554432 Postscale*(9.6 hours)
#FUSES DSWDT_=12 // *DSWDT_9HRS (compiler 5.090 has an issue with this fuse, so adopt this work-around)
#FUSES NOPROTECT // Allow a Programmer device (eg. Pickit) to read Microcontroller firmware
|
Do they allow the selections to be changed more than once?
If not, how can I change them ?
Regards |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Mon Aug 03, 2020 7:52 am |
|
|
You need to add the fuse NOIOL1WAY
Then the point is that the existing code sets the pin up, but in your sleep
and wake up code you need to add the 'in code' version of pin_select as I
show. What happens is the the standard #PIN_SELECT sets the pin to be
controlled by the SPI peripheral. These lines allow this control to be turned
'off' by instead setting the pin to the 'NULL' device. Then when the chip
wakes the connection back to the SPI has to be re-made.
This line:
pin_select(NULL,PIN_D4);
Disconnects D4, from the SPI peripheral, then this line:
pin_select(SCLK2,PIN_D4);
Connects it back to the peripheral.
Between these, the normal 'output_low' instruction can work. |
|
|
Marco27293
Joined: 09 May 2020 Posts: 126
|
|
Posted: Mon Sep 21, 2020 6:52 am |
|
|
Hi everyone,
I'm facing a weird problem using a MicroSD and the library posted in this topic.
Sometimes (5% of all cases) when I try to read data stored in the MicroSD it seems that the RAM buffer does not correctly load data from the card.
The function mmcsd_read_data(a, n, p) returns 0 with success but the data read are the last data previously written during the data acquisition process and buffer content does not change its content.
Any suggestion regarding issue cause ?
I think it could be a bug of mmcsd.c driver, I need help to fix it.
Regards |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Mon Sep 21, 2020 7:03 am |
|
|
Are you sure you are updating the address required correctly?. The
read_data function will not perform a transfer and will return 0, if the
address requested is the same as the last one used. It assumes in this
case that since you just wrote the data, what is in the buffer is the data
required. |
|
|
Marco27293
Joined: 09 May 2020 Posts: 126
|
|
Posted: Mon Sep 21, 2020 7:33 am |
|
|
yes I'm sure
Code: |
void Send_IMG_bytes_from_MicroSD(int32 size,int32 Address,int8 portion)
{
fail_safe_wd=0;
int8 data,res;
int32 memAddress=Address;
int32 counter=0;
while(counter<size)
{
res=mmcsd_read_data(memAddress, 1, &data);
if(res==0)
{
counter++;
memAddress++;
if((debug)&&(counter<1024)) usb_cdc_putc(data);
}
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Mon Sep 21, 2020 8:05 am |
|
|
Er. It won't load any new data.
The read_byte routine, loads a block of data into g_mmcsd_buffer. It then
returns the data from the requested index in this buffer.
*data = g_mmcsd_buffer[addr % MMCSD_MAX_BLOCK_SIZE];
So a read to change the data will only occur every
MMCSD_MAX_BLOCK_SIZE bytes, |
|
|
Marco27293
Joined: 09 May 2020 Posts: 126
|
|
Posted: Tue Sep 22, 2020 1:18 am |
|
|
I got this point.
The problem is : while loop cycles over thousands of sequential data, but I always read the same 512 bytes.
When the buffer overflows no new buffer is loaded, it is a weird issue because happens in 5-10% of cases.
In a lot of other tests MicroSD is correctly read and nothing changes in hardware or firmware...
I really need to overcome this problem but I have no idea on what is causing it.
Regards |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Tue Sep 22, 2020 1:43 am |
|
|
Test if it is actually calling the mmcsd_load_buffer routine?. This is what
actually loads new data into the buffer. The value of g_mmcsdBufferAddress
when this is called, is the 'block number' to be loaded. This (obviously)
should be changing to match the new sector to load. If this is not being called
than an error is occurring, but the question is whey it is not being flagged
as such. If it is being called, and the sector number is changing, then instead
we need to work out why this is not actually working.... |
|
|
Marco27293
Joined: 09 May 2020 Posts: 126
|
|
Posted: Tue Sep 22, 2020 7:20 am |
|
|
mmcsd_load_buffer routine is correctly called.
g_mmcsdBufferAddress is correctly updated.
The bug persists... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Tue Sep 22, 2020 8:05 am |
|
|
OK. What has to be happening is that when it calls 'wait_for_token', it is
retrieving a value of zero. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|