Spark Logic

SD only partially works.

RogerClark Sat Jun 06, 2015 6:06 am

I don’t know if this is just me, but SD seems really flakey

The cardinfo demo seems really reliable, but the other demo’s that read and write files seem pretty hit and miss.

I’m not sure if this is because the default speed for the SD Lib is HALF speed. But on STM32 that HALF speed on SPI may be too fast for some SD Cards, especially the cheap ones.

Has anyone else experienced problems reading and writing files to SD ?

Replies

pico Mon Jun 08, 2015 8:45 am

RogerClark wrote:So I think the status of the SD lib, is it does work, but only if you don’t use PA4 for CS

pico Mon Jun 08, 2015 8:56 am

Now, a bit of googling suggests there may be some inherent weirdness in the F103 silicon re the CSN pin behaviour.

Here’s a quote from a forum post on STM in 2012:

Confirmed here (on the STM3240G-EVAL board), also with setting the NSS on PB9 instead of PB12. The NSS pin stays low. When set to TI mode, it starts toggling, so the GPIO- and AF-setting is correct.In “standard” mode it stays low even if the enable bit (CR1.6) is cleared.

I’d say this is simply a design flaw, covered up partially by the following sentence in the manual:

“Note: When a master is communicating with SPI slaves which need to be de-selected between transmissions, the NSS pin must be configured as GPIO or another GPIO must be used and toggled by software.”

It would be nice to hear some comment from ST.

JW

Here’s a link to the forum page on my.st.com with that post:

https://my.st.com/public/STe2ecommuniti … views=1705

So it looks like even one ST manual is saying the CSN needs manual control from a GPIO other pin than the hardware ports designated CSNs!

Note that even this doesn’t override the weird behaviour:

pinMode(BOARD_SPI2_NSS_PIN, OUTPUT);
:
:
digitalWrite(BOARD_SPI2_NSS_PIN, LOW);
SPI_2.transfer(b);
digitalWrite(BOARD_SPI2_NSS_PIN, HIGH);

madias Mon Jun 08, 2015 8:57 am

….and if the slave is not totally overwhelmed, then comes the “bang” at the latest here:
Image
EDIT: So the best workaround would be to deselect the NSS pin in the SPI library (and using it as normal GPIO) and toogle it per hand or within a wise library addon

pico Mon Jun 08, 2015 9:43 am

madias wrote:EDIT: So the best workaround would be to deselect the NSS pin in the SPI library (and using it as normal GPIO) and toogle it per hand or within a wise library addon

RogerClark Mon Jun 08, 2015 10:00 am

Umm

There is some stuff on page 694 of the manual

Slave select (NSS) pin management
Hardware or software slave select management can be set using the SSM bit in the
SPI_CR1 register.
• Software NSS management (SSM = 1)
The slave select information is driven internally by the value of the SSI bit in the
SPI_CR1 register. The external NSS pin remains free for other application uses.

pico Mon Jun 08, 2015 10:11 am

RogerClark wrote:Umm

There is some stuff on page 694 of the manual

Slave select (NSS) pin management
Hardware or software slave select management can be set using the SSM bit in the
SPI_CR1 register.
• Software NSS management (SSM = 1)
The slave select information is driven internally by the value of the SSI bit in the
SPI_CR1 register. The external NSS pin remains free for other application uses.

Vassilis Mon Jun 08, 2015 10:17 am

Today I found some time to test the default arduino SD library (SD) with my STM32F103CT8.
At the first, It didn’t worked (at least to me). But after a few additional lines to the standard library it worked.

Edit the file Sd2PinMap.h (arduino-1.6.4\libraries\SD\src\utility) and add following lines:

//------------------------------------------------------------------------------
#elif defined(__STM32F1__)
uint8_t const SS_PIN = PA4;
uint8_t const MOSI_PIN = PA7;
uint8_t const MISO_PIN = PA6;
uint8_t const SCK_PIN = PA5;
//------------------------------------------------------------------------------

RogerClark Mon Jun 08, 2015 10:23 am

I just tried changing the flags

by adding SPI_CR1_SSM_BIT

uint32 flags = ((bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT | SPI_SW_SLAVE | SPI_SOFT_SS | SPI_CR1_SSM_BIT);

RogerClark Mon Jun 08, 2015 10:25 am

Vasillis

We alrready have definitions (placeholders )

#warning these are just here to get SPI to compile they need to be changed and moved!
#define SS (1)
#define MOSI 2
#define MISO 3
#define SCK 4

RogerClark Mon Jun 08, 2015 10:36 am

We need a gpio_get_mode() that does the reverse of

void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) {
gpio_reg_map *regs = dev->regs;
__io uint32 *cr = &regs->CRL + (pin >> 3);
uint32 shift = (pin & 0x7) * 4;
uint32 tmp = *cr;

tmp &= ~(0xF << shift);
tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift;
*cr = tmp;

if (mode == GPIO_INPUT_PD) {
regs->ODR &= ~(1U << pin);
} else if (mode == GPIO_INPUT_PU) {
regs->ODR |= (1U << pin);
}
}

Vassilis Mon Jun 08, 2015 10:47 am

I think there is a pinMap error. It seems that when you define a pin with a plain number (2, 3, 4, etc) the definition wont work.
That’s why I always use the PXX or PXXX syntax when I define a pin.

pico Mon Jun 08, 2015 11:14 am

RogerClark wrote:
Slave select (NSS) pin management
Hardware or software slave select management can be set using the SSM bit in the
SPI_CR1 register.
• Software NSS management (SSM = 1)
The slave select information is driven internally by the value of the SSI bit in the
SPI_CR1 register. The external NSS pin remains free for other application uses.

RogerClark Mon Jun 08, 2015 11:21 am

The manual, RM00008 seems to imply that MSS needs to be set


Software NSS management (SSM = 1)
The slave select information is driven internally by the value of the SSI bit in the
SPI_CR1 register. The external NSS pin remains free for other application uses.

But it’s worth trying the other combinations, as the manual is sometimes wrong

pico Mon Jun 08, 2015 12:05 pm

pico wrote:I will experiment.

pico Mon Jun 08, 2015 3:41 pm

pico wrote:[…]but there does seem to be some hope that the CSN pins should be able to be toggled manually in gpio mode — which although not ideal, would be better than nothing.

sheepdoll Mon Jun 08, 2015 9:18 pm

I actually ran into this same problem on AVR using the NSS pin. On the AVR the NSS pin is used to set Master/Slave. So when ever the NSS pin was written low, it was putting SPI into slave mode. Now when I code SPI, I think of the NSS pin being an input to the mPU.

As for an SD library, I use Chan’s FatFS and PetiteFatFS. I think the “Middleware” Code STM32CubeMX includes is the same library as the link will lead to the elmChan site. This code will even run on an AVRtiny45 top play *.WAV files. (Had to hack some of it to do so.) Runs quite well on a AVRTiny85 with room to spare. I did a project which was a toy piano where we made 333 units using a AVRtiny85. The smallest card I could get in bulk was like 4 gigabytes.

I like the idea of using a second data logging processor to handle the SPI read/write to the card. Especially the FAT writes to dynamically allocated files. Reading is not much of an issue. Writing at audio/video rates can be a problem, when the FAT starts getting full, or the disk badly fragmented, and there are long searches needed to find free allocation blocks.

I have been concerned with the pipe organ record on the faster stm32 and the slower SD cards. Being able to use a second processor to handle the dynamic FAT allocation and directory updates asynchronously, may be the answer.

Roger: if you have not done so, look at how elm chan (who is really the cat) did the 8 pin wave player with the AVRTiny85. The bottleneck procs are in AVR asm, but it does show how to set up the buffers for direct playback. Sort of a psudo DMA.

RogerClark Mon Jun 08, 2015 9:46 pm

Pico

I came to the same conclusion.

If you set pinMode after Begin its ok. I.e SPI doesn’t seem to clash with using the pin as GPIO.

However begin() is also called in setDivider() and setBitOrder as all thse functions basically have to configure the SPI control reg.

So the quick and dirty fix is to set PA4 to OUTPUT at the end of the begin() function.

we need to handle SPI2 and on some boards also SPI3. But we can put in a switch() to handle this.

But, I’m a bit concerned about the code putting pins into OUTPUT , in case for some bizarre reason, someone had for example decided to use PA4 as an input for flow control, like the Data Req line on the VS1003. As in that case, it would potentially damage some hardware.

So..
I think the best option is to write some code to get the pinMode of the relevant NSS pin before setting the SPI control reg, and then set the pinMode back to the saved state after setting the SPI control reg.

I know this will marginally slow things down, but SPI begin() is not normally called in time critical locations in the code.

@sheepdoll

Thanks for the info on the other File System code.

Using SD is a pain, as it only allows one file handle open at a time :-(
So I can even get a directory list, and then play the files one by one, because the directory list needs a file handle.

I did try writing a work around for the directory list stuff ( as I didnt need recursion into directories, I just stored how many files in the directory, that the MP3 player had played, then started each directory listing from the beginning and skipped over N files to get to the next one to play; but its all a bit hacky) I did consider a linked list for my files list, but malloc is likely to allocate loads of mem for a 8 + 3 file name string, so gave up on that idea.

I think in the longer term we should be able to get the latest version of SdFat working, as it somehow works for Victor.

sheepdoll Mon Jun 08, 2015 11:08 pm

RogerClark wrote:

Using SD is a pain, as it only allows one file handle open at a time :-(
So I can even get a directory list, and then play the files one by one, because the directory list needs a file handle.

RogerClark Mon Jun 08, 2015 11:44 pm

@sheepdoll

I’d tried to use the listfiles demo, and then for each file it iterated, I called my playFile(char *fileName) function

But playFile needs to open the file to plat, and the listfiles loop still has the “dir” file open.

So what seems to happen is it plays the first file, but when playFile function returned, the dir file handle seemed to have been corrupted because playfile has open a file to play

I thought that there was something in the SD lib that uses a global for the file it has open.

But perhaps what was really going on was that the SD read code was getting knackered because of the issues with Chip Select on PA4 not really working.

I’ll need to have another go at using the code from the listfiles example

I could just allocate a big array for the filenames, but it seemed like a hacky way to do it.

sheepdoll Tue Jun 09, 2015 12:32 am

RogerClark wrote:I could just allocate a big array for the filenames, but it seemed like a hacky way to do it.

Sign in to reply