Blue pill and SD card

Generic boards that are not Maple or Maple mini clones, and don't contain the additional USB reset hardware
skematic
Posts: 6
Joined: Tue May 23, 2017 11:36 am

Blue pill and SD card

Post by skematic » Tue May 23, 2017 10:47 pm

I've been trying to get the blue pill work with my SD card module. The SD module works with arduino, however none of the libraries I'm familiar with seems to work with the stm32f103.
My connections (SD module -> blue pill)
CS -> PA15
SCK -> PB3
MISO-> PB4
MOSI -> PB5
GND->GND
VCC connected to external 5V


SD library's CardInfo:

Code: Select all

/*
  SD card test

 This example shows how use the utility libraries on which the'
 SD library is based in order to get info about your SD card.
 Very useful for testing a card when you're not sure whether its working or not.

 The circuit:
  * SD card attached to SPI bus as follows:
 ** MOSI - pin 11 on Arduino Uno/Duemilanove/Diecimila
 ** MISO - pin 12 on Arduino Uno/Duemilanove/Diecimila
 ** CLK - pin 13 on Arduino Uno/Duemilanove/Diecimila
 ** CS - depends on your SD card shield or module.
 		Pin 4 used here for consistency with other Arduino examples


 created  28 Mar 2011
 by Limor Fried
 modified 9 Apr 2012
 by Tom Igoe
 */
// include the SD library:
#include <SPI.h>
#include <SD.h>

// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;

// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
const int chipSelect = PA15;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  Serial.print("\nInitializing SD card...");

  // we'll use the initialization code from the utility libraries
  // since we're just testing if the card is working!
  if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card inserted?");
    Serial.println("* is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
    return;
  } else {
    Serial.println("Wiring is correct and a card is present.");
  }

  // print the type of card
  Serial.print("\nCard type: ");
  switch (card.type()) {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;
    case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;
    case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC");
      break;
    default:
      Serial.println("Unknown");
  }

  // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
  if (!volume.init(card)) {
    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
    return;
  }


  // print the type and size of the first FAT-type volume
  uint32_t volumesize;
  Serial.print("\nVolume type is FAT");
  Serial.println(volume.fatType(), DEC);
  Serial.println();

  volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
  volumesize *= volume.clusterCount();       // we'll have a lot of clusters
  volumesize *= 512;                            // SD card blocks are always 512 bytes
  Serial.print("Volume size (bytes): ");
  Serial.println(volumesize);
  Serial.print("Volume size (Kbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);
  Serial.print("Volume size (Mbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);


  Serial.println("\nFiles found on the card (name, date and size in bytes): ");
  root.openRoot(volume);

  // list all files in the card with date and size
  root.ls(LS_R | LS_DATE | LS_SIZE);
}


void loop(void) {

}
outputs

Code: Select all

ializing SD card...initialization failed. Things to check:
* is a card inserted?
* is your wiring correct?
* did you change the chipSelect pin to match your shield or module?
SdFat's SdInfo:

Code: Select all

/*
 * This program attempts to initialize an SD card and analyze its structure.
 */
#include <SPI.h>
#include "SdFat.h"
/*
 * SD chip select pin.  Common values are:
 *
 * Arduino Ethernet shield, pin 4.
 * SparkFun SD shield, pin 8.
 * Adafruit SD shields and modules, pin 10.
 * Default SD chip select is the SPI SS pin.
 */
const uint8_t SD_CHIP_SELECT = PA15;
/*
 * Set DISABLE_CHIP_SELECT to disable a second SPI device.
 * For example, with the Ethernet shield, set DISABLE_CHIP_SELECT
 * to 10 to disable the Ethernet controller.
 */
const int8_t DISABLE_CHIP_SELECT = -1;
SdFat sd;

// serial output steam
ArduinoOutStream cout(Serial);

// global for card size
uint32_t cardSize;

// global for card erase size
uint32_t eraseSize;
//------------------------------------------------------------------------------
// store error strings in flash
#define sdErrorMsg(msg) sdErrorMsg_F(F(msg));
void sdErrorMsg_F(const __FlashStringHelper* str) {
  cout << str << endl;
  if (sd.card()->errorCode()) {
    cout << F("SD errorCode: ");
    cout << hex << int(sd.card()->errorCode()) << endl;
    cout << F("SD errorData: ");
    cout << int(sd.card()->errorData()) << dec << endl;
  }
}
//------------------------------------------------------------------------------
uint8_t cidDmp() {
  cid_t cid;
  if (!sd.card()->readCID(&cid)) {
    sdErrorMsg("readCID failed");
    return false;
  }
  cout << F("\nManufacturer ID: ");
  cout << hex << int(cid.mid) << dec << endl;
  cout << F("OEM ID: ") << cid.oid[0] << cid.oid[1] << endl;
  cout << F("Product: ");
  for (uint8_t i = 0; i < 5; i++) {
    cout << cid.pnm[i];
  }
  cout << F("\nVersion: ");
  cout << int(cid.prv_n) << '.' << int(cid.prv_m) << endl;
  cout << F("Serial number: ") << hex << cid.psn << dec << endl;
  cout << F("Manufacturing date: ");
  cout << int(cid.mdt_month) << '/';
  cout << (2000 + cid.mdt_year_low + 10 * cid.mdt_year_high) << endl;
  cout << endl;
  return true;
}
//------------------------------------------------------------------------------
uint8_t csdDmp() {
  csd_t csd;
  uint8_t eraseSingleBlock;
  if (!sd.card()->readCSD(&csd)) {
    sdErrorMsg("readCSD failed");
    return false;
  }
  if (csd.v1.csd_ver == 0) {
    eraseSingleBlock = csd.v1.erase_blk_en;
    eraseSize = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
  } else if (csd.v2.csd_ver == 1) {
    eraseSingleBlock = csd.v2.erase_blk_en;
    eraseSize = (csd.v2.sector_size_high << 1) | csd.v2.sector_size_low;
  } else {
    cout << F("csd version error\n");
    return false;
  }
  eraseSize++;
  cout << F("cardSize: ") << 0.000512*cardSize;
  cout << F(" MB (MB = 1,000,000 bytes)\n");

  cout << F("flashEraseSize: ") << int(eraseSize) << F(" blocks\n");
  cout << F("eraseSingleBlock: ");
  if (eraseSingleBlock) {
    cout << F("true\n");
  } else {
    cout << F("false\n");
  }
  return true;
}
//------------------------------------------------------------------------------
// print partition table
uint8_t partDmp() {
  cache_t *p = sd.vol()->cacheClear();
  if (!p) {
    sdErrorMsg("cacheClear failed");
    return false;
  }
  if (!sd.card()->readBlock(0, p->data)) {
    sdErrorMsg("read MBR failed");
    return false;
  }
  for (uint8_t ip = 1; ip < 5; ip++) {
    part_t *pt = &p->mbr.part[ip - 1];
    if ((pt->boot & 0X7F) != 0 || pt->firstSector > cardSize) {
      cout << F("\nNo MBR. Assuming Super Floppy format.\n");
      return true;
    }
  }
  cout << F("\nSD Partition Table\n");
  cout << F("part,boot,type,start,length\n");
  for (uint8_t ip = 1; ip < 5; ip++) {
    part_t *pt = &p->mbr.part[ip - 1];
    cout << int(ip) << ',' << hex << int(pt->boot) << ',' << int(pt->type);
    cout << dec << ',' << pt->firstSector <<',' << pt->totalSectors << endl;
  }
  return true;
}
//------------------------------------------------------------------------------
void volDmp() {
  cout << F("\nVolume is FAT") << int(sd.vol()->fatType()) << endl;
  cout << F("blocksPerCluster: ") << int(sd.vol()->blocksPerCluster()) << endl;
  cout << F("clusterCount: ") << sd.vol()->clusterCount() << endl;
  cout << F("freeClusters: ");
  uint32_t volFree = sd.vol()->freeClusterCount();
  cout <<  volFree << endl;
  float fs = 0.000512*volFree*sd.vol()->blocksPerCluster();
  cout << F("freeSpace: ") << fs << F(" MB (MB = 1,000,000 bytes)\n");
  cout << F("fatStartBlock: ") << sd.vol()->fatStartBlock() << endl;
  cout << F("fatCount: ") << int(sd.vol()->fatCount()) << endl;
  cout << F("blocksPerFat: ") << sd.vol()->blocksPerFat() << endl;
  cout << F("rootDirStart: ") << sd.vol()->rootDirStart() << endl;
  cout << F("dataStartBlock: ") << sd.vol()->dataStartBlock() << endl;
  if (sd.vol()->dataStartBlock() % eraseSize) {
    cout << F("Data area is not aligned on flash erase boundaries!\n");
    cout << F("Download and use formatter from www.sdcard.org!\n");
  }
}
//------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  
  // Wait for USB Serial 
  while (!Serial) {
    SysCall::yield();
  }

  // use uppercase in hex and use 0X base prefix
  cout << uppercase << showbase << endl;

  // F stores strings in flash to save RAM
  cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
  if (DISABLE_CHIP_SELECT < 0) {
    cout << F(
           "\nAssuming the SD is the only SPI device.\n"
           "Edit DISABLE_CHIP_SELECT to disable another device.\n");
  } else {
    cout << F("\nDisabling SPI device on pin ");
    cout << int(DISABLE_CHIP_SELECT) << endl;
    pinMode(DISABLE_CHIP_SELECT, OUTPUT);
    digitalWrite(DISABLE_CHIP_SELECT, HIGH);
  }
  cout << F("\nAssuming the SD chip select pin is: ") <<int(SD_CHIP_SELECT);
  cout << F("\nEdit SD_CHIP_SELECT to change the SD chip select pin.\n");
}
//------------------------------------------------------------------------------
void loop() {
  // Read any existing Serial data.
  do {
    delay(10);
  } while (Serial.available() && Serial.read() >= 0);

  // F stores strings in flash to save RAM
  cout << F("\ntype any character to start\n");
  while (!Serial.available()) {
    SysCall::yield();
  }

  uint32_t t = millis();
  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards.  use SPI_FULL_SPEED for better performance.
  if (!sd.cardBegin(SD_CHIP_SELECT, SPI_HALF_SPEED)) {
    sdErrorMsg("\ncardBegin failed");
    return;
  }
  t = millis() - t;

  cardSize = sd.card()->cardSize();
  if (cardSize == 0) {
    sdErrorMsg("cardSize failed");
    return;
  }
  cout << F("\ninit time: ") << t << " ms" << endl;
  cout << F("\nCard type: ");
  switch (sd.card()->type()) {
  case SD_CARD_TYPE_SD1:
    cout << F("SD1\n");
    break;

  case SD_CARD_TYPE_SD2:
    cout << F("SD2\n");
    break;

  case SD_CARD_TYPE_SDHC:
    if (cardSize < 70000000) {
      cout << F("SDHC\n");
    } else {
      cout << F("SDXC\n");
    }
    break;

  default:
    cout << F("Unknown\n");
  }
  if (!cidDmp()) {
    return;
  }
  if (!csdDmp()) {
    return;
  }
  uint32_t ocr;
  if (!sd.card()->readOCR(&ocr)) {
    sdErrorMsg("\nreadOCR failed");
    return;
  }
  cout << F("OCR: ") << hex << ocr << dec << endl;
  if (!partDmp()) {
    return;
  }
  if (!sd.fsBegin()) {
    sdErrorMsg("\nFile System initialization failed.\n");
    return;
  }
  volDmp();
}
outputs

Code: Select all

Assuming the SD is the only SPI device.
Edit DISABLE_CHIP_SELECT to disable another device.

Assuming the SD chip select pin is: 15
Edit SD_CHIP_SELECT to change the SD chip select pin.

type any character to start

cardBegin failed
SD errorCode: 0X1
SD errorData: 0XFF

type any character to start
I'm using this module
Image

Someone help please

User avatar
RogerClark
Posts: 7157
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Blue pill and SD card

Post by RogerClark » Wed May 24, 2017 4:23 am

Looks like it has a level converter to work with 5V AVR hardware.

It may not work with 3.3V STM32 hardware, as the level converter is not required (and most likely will cause incorrect voltage levels to be sent to the SD Card)

ag123
Posts: 770
Joined: Thu Jul 21, 2016 4:24 pm

Re: Blue pill and SD card

Post by ag123 » Wed May 24, 2017 9:41 am

get those without a level converter and without series resistors, pullups meeting the sd specs is ok, but series resistors probably make things worse by forming an RC circuit distorting the signals in the mhz ranges
http://www.ebay.com/sch/i.html?_from=R4 ... duino+3.3v

skematic
Posts: 6
Joined: Tue May 23, 2017 11:36 am

Re: Blue pill and SD card

Post by skematic » Wed May 24, 2017 9:54 am

I will order one with 3.3V logic voltage.

In the mean time I want to start experimenting with SD. I've tried using a logic level converter for the SPI lines between the STM32F103 and SD module, however results are also disappointing (maybe the level converter is too slow?). Is there no way to get started with the SD module I currently have?

Image

ag123
Posts: 770
Joined: Thu Jul 21, 2016 4:24 pm

Re: Blue pill and SD card

Post by ag123 » Wed May 24, 2017 10:06 am

i think sd cards are fussy with voltage levels, in particular the vcc and ground supply voltages, 3.3v after a dropout LDO is possibly left around 2.2v, then *series* resistors probably distort signals in the mhz ranges, pull ups meeting the sd specs is ok.
what may be attempted though is start with low spi clock speeds

it seem those 3.3v tf micro-sd adaptors less those series resistors are 'hard to find' on ebay, a lot of them put series resistors or some level translators and labled that 3.3v/5v. but i think this impact the performance for 3.3v ones once you raise the spi clock to mhz ranges, but that's where we want to operate, otherwise you may end up with transfer speeds say in the low hundreds kbytes/s possibly <100kbytes/s at best

what i did is i removed 3 series resistors (replaced with wires) on my ili9341 lcd with a sd adapter and used that adaptor
http://www.stm32duino.com/viewtopic.php?f=44&t=2026

note that your adapter seem to be using a buffer/transceiver IC, i think buffer ICs should still work for the data lines.
but if you want to power the card, you may want to try to find a 5v voltage source if you want to connect before the LDO
if you make do with 3.3v across the LDO, the dropout is likely to be at least 0.5v (leaving 2.7v) or some cases 1v (leaving 2.2v)

but do be careful about putting a 5V VCC as that could possibly damage STM32F1 chip and or SD if done incorrectly, SPI 1 on stm32f103 is on analog pins which is not 5V tolerant

User avatar
RogerClark
Posts: 7157
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Blue pill and SD card

Post by RogerClark » Wed May 24, 2017 10:32 am

It looks like the level converter chip just takes MOSI and SCLK and converts them to 3.3V, its hard to see if it does MISO by looking at the photos

You could try unsoldering the level converter and carefully soldering the inputs to the outputs for MOSI and SCLK.

But as @ag123 said, there may also be problems with the regulator, so make sure you supply it with 5V or alternatively connect the 3.3V to the output of the voltage regulator.
You may need to remove in the voltage regulator as well, but in my experience, the ones I've used, do not seem to draw current in through their output if supplied with 3.3V

stevestrong
Posts: 1747
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany

Re: Blue pill and SD card

Post by stevestrong » Wed May 24, 2017 1:12 pm

As @ag123 said, lower the SPI speed when using the level translator.

skematic
Posts: 6
Joined: Tue May 23, 2017 11:36 am

Re: Blue pill and SD card

Post by skematic » Wed May 24, 2017 10:47 pm

Thank you for all the feedback.

It seems at least some modifications is required to my current SD module, however if possible I'd like to stray away from SMD soldering :) Would some header pins soldered directly to the pins of a microSD-to-SD adapter work instead? I've looked up the pins from an SD card, seems like there are SPI lines available and are 3.3V tolerant. I went ahead and soldered some header pins to the microSD adapter.(not my picture but looks very similar) I've put the SD module aside and connected the SD card directly to the microcontroller board.

Communication with an 3.3V arduino pro mini works fine! Both library outputs correct information about the inserted SD card and lists all files on the storage card.
On the STM32f103 it at least recognizes an SD card, however it is still running into troubles (correct card size 8GB);

SD library's CardInfo.ino serial output (code in opening post):

Code: Select all

ializing SD card...Wiring is correct and a card is present.

Card type: SD2
Could not find FAT16/FAT32 partition.
Make sure you've formatted the card
SdFat's SdInfo.ino serial output (code in opening post):

Code: Select all

sion: 20160719

Assuming the SD is the only SPI device.
Edit DISABLE_CHIP_SELECT to disable another device.

Assuming the SD chip select pin is: 4
Edit SD_CHIP_SELECT to change the SD chip select pin.

type any character to start

init time: 1 ms

Card type: SD2

Manufacturer ID: 0X0
OEM ID:
Product: 
Version: 0.0
Serial number: 0X0
Manufacturing date: 0/2000

cardSize: 127.14 MB (MB = 1,000,000 bytes)
flashEraseSize: 128 blocks
eraseSingleBlock: true
OCR: 0X80FF8000

No MBR. Assuming Super Floppy format.

File System initialization failed.


type any character to start
Why would it work on arduino pro mini 3.3v but not on the blue pill? I want to try lowering SPI speed, where can I do this?
Last edited by skematic on Wed May 24, 2017 11:29 pm, edited 1 time in total.

stevestrong
Posts: 1747
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany

Re: Blue pill and SD card

Post by stevestrong » Wed May 24, 2017 11:19 pm

skematic wrote:I want to try lowering SPI speed, where can I do this?
In the main loop, you have:

Code: Select all

  if (!sd.cardBegin(SD_CHIP_SELECT, SPI_HALF_SPEED)) {
Replace "SPI_HALF_SPEED" by "SPI_CLOCK_DIV8" (or 16 instead of 8)

skematic
Posts: 6
Joined: Tue May 23, 2017 11:36 am

Re: Blue pill and SD card

Post by skematic » Wed May 24, 2017 11:36 pm

stevestrong wrote:
skematic wrote:I want to try lowering SPI speed, where can I do this?
In the main loop, you have:

Code: Select all

  if (!sd.cardBegin(SD_CHIP_SELECT, SPI_HALF_SPEED)) {
Replace "SPI_HALF_SPEED" by "SPI_CLOCK_DIV8" (or 16 instead of 8)
Tried 4, 8, 16 up to 256. Same results for SdInfo. CardInfo fails initializing the card.

Post Reply