Petit FatFS slow reading speed [ATtiny85]

Go To Last Post
21 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This project http://elm-chan.org/works/sd8p/r... uses the petit fatfs library to read wav files off of SD cards and play them flawlessly without any problems, but in my project (project zip in attachments) the sound is pulsing, most likely because pf_read() takes a lot of time to do its stuff and when it is ready it uses disk_readp(), which calls playsample() that sets the pwm duty cycle of the sound output, which results a sound like this (output.wav in zip), it is supposed to be a 500Hz square wave. Does anybody know how to fix that?           

Attachment(s): 

Last Edited: Fri. Mar 30, 2018 - 09:01 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The way to fix it is to pick a more appropriate AVR ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What do you mean? I only want to do this with an attiny85 because it is so small, also the project by chan used an attiny85 and it worked for him. And i forgot to mention that i did the same thing before with an atmega328p and had exactly the same results, so the problem is not in the AVR

Last Edited: Fri. Mar 30, 2018 - 09:30 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you use a larger AVR you can use FatFs which buffers. PetitFs is a "kludge" simply to give you something but no one ever said that it was high performance. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So what am i doing wrong? How did chan get it to work? Also, i used FatFS on an Atmega328p before to play wav files from SD cards and had exactly the same results

Last Edited: Fri. Mar 30, 2018 - 10:04 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well if you have implemented everything as Chan showed and it "pulses" it sounds most like a wiring error. But understand that Chan did projects like this to show the very limits of what his software could achieve. Not really to show practical solutions. Anyone doing a sound sample playing AVR project would usually choose a decent sized AVR, one that can support running the full FatFs version.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I haven't implemented everything as Chan, that is the reason i am here, to find out what is different in my code that slows down pf_read

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well for that we need to see your exact schematic and code. But why not start by implementing exactly what Chan has then, when that's "proven", start to adapt it to your own design?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Code is in the forum post attachments, schematic here. I don't really want to start from Chan's code and start modifying it because i don't understand most of it, i want to make my own code which i can understand.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also the pf files in Chan's wav player look like they are exactly the same as mine, but i still can't figure out what makes his code work

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You should also post the original wav file you have on the SD card.  Without it, there's only so much we can guess.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here you go

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One of the dominant limiting speed factors is the SPI clock rate. What have you set that to?

 

Jim

 

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So the original is 8bit 44.1 kHz.  The stuttering is regularly spaced at 0.0664 seconds.  This corresponds to about 2900 samples.  This does >>not<< correspond to the sector size of 512 bytes, nor the pf sub-sector size.  So not very revealing.

 

I took a quick look at your code, and I'd have to say you don't yet have an understanding of how to generate sound from an AVR.  For one, your playsample() function (which inexplicably is called from diskreadp() in mmcbbp.c) blocks on a timer flag.  This means that every time you play a sample, you're wasting cycles when you could be fetching the next samples.

 

You say:

I don't really want to start from Chan's code and start modifying it because i don't understand most of it, i want to make my own code which i can understand.

I urge you to reconsider.  Study known good working code.  If you have trouble understanding as aspect of it, ask a question.  Don't stab blindly into the dark.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lol sorry, the original file had a bitrate of 16kHz, i just didnt bother copying the original file from the SD card to my pc so i just created a new one and forgot to change the rate. Here is the file that was on the SD card. Also i'm not very comfortable with reading very long assembly code, which is 'read_blk_part' in Chan's code, that's why i said that. Also i tried before with pf_read in an ISR that is called 16000 times a second, but that was tooo slow, so i'd really like to know how to do this with interrupts

Attachment(s): 

Last Edited: Fri. Mar 30, 2018 - 05:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lol sorry, the original file had a bitrate of 16kHz, i just didnt bother copying the original file from the SD card to my pc so i just created a new one and forgot to change the rate. Here is the file that was on the SD card.

 

[sigh]  Let that be a lesson.  Don't waste the time of those from whom you've solicited help by providing inaccurate information.  To do so knowingly is doubly insulting.

 

At 16 kHz, it means that you're getting through about 1000 bytes of samples, or two sectors, before your SD card fetch code can't keep up with the PWM code.

 

Also i'm not very comfortable with reading very long assembly code

The study someone else's code written in C.  There must be dozens of projects out there.

 

The general approach:

  • set up an interrupt to pull bytes from an SRAM buffer and feed the PWM output AT THE DESIRED SAMPLE RATE.
  • wait until there is room in the buffer for a new block of data
  • fetch a block of data from the SD card and place it into the buffer
  • wait until there is room in the buffer for a new block of data
  • fetch a block of data from the SD card and place it into the buffer
  • wait until there is room in the buffer for a new block of data
  • fetch a block of data from the SD card and place it into the buffer
  • ...
  • ...

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Fri. Mar 30, 2018 - 05:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry about that. I'll try the general approach, thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've tried something like you said, but i got the same result which was even slower at 44.1kHz, project in attachments. I tried searching for ATtiny85 wav player or petit fatfs wav player, but the things i found either used the code by Chan or didn't provide the source code.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So for a 16 kHz wave file, the sample engine (via TIMER0) runs in CTC mode with prescaler 8 and a top of 87, for an ISR period of 8 * (87 + 1) = 704 cpu cycles.  If that's representative of a 16 kHz wav file, then the t85 should be running at 11.264 MHz.

 

That's a number seemingly pulled out of a hat.

 

How fast is your t85 actually running?  And how have you confirmed that?

 

The original wav file is bang on 500 Hz, but the output.wav file shows just shy of 550 Hz.  If the 11.264 MHz calculation above is accurate, this implies that the actual speed of the t85 is in fact 12.39 MHz.  Yet another magic number.

 

There are other oddities in your code, like:

extern void playsample(uint8_t sample) {
	OCR1A = sample;
	TCCR0B = 0;
	TIFR |= ~(1 << OCF0A);
	TCNT0 = 0;
	TCCR0B |= (prescaler & 7);
	while(!(TIFR & (1 << OCF0A)));
	TCCR0B = 0;
}

Why on earth are you stopping, resetting, and restarting the sample timer as part of playing a sample?  that's going to throw off the timing of the sample ISR in ways that are difficult to predict.

 

If your t85 is in fact running at or near 12 MHz, that likely explains the underlying issue.  Not enough CPU cycles available to do the work.  The t85 can run at 16 MHz from the internal RC oscillator via the PLL clock.

 

If the apparent 12 MHz is a consequence of the stop/reset/start action of playsample(), and your t85 is in fact only running at 8 MHz, then that would make matters even worse.

 

I've stared at your code for long enough.  It's seems to be needlessly complicated (and huge blocks of code commented away does not help readability).  It really is about as simple as setting up a buffer-fed sample-engine ISR, and feeding that buffer via pf_read().  After the initialisation code, the whole thing should be less than 20 lines of code (not including the pf files).

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MY t85 is running at 16MHz off of PLL, in ATtiny85_SD_new.zip i do not use playsample(), i use ISR(TIMER0_COMPA_vect), which increments bufptr, disk_readp waits until bufptr is higher than bufptr2, after that it stores the next sample in samplebuf and increments bufptr2 and starts over and so on

Last Edited: Sat. Mar 31, 2018 - 09:28 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MY t85 is running at 16MHz off of PLL, in ATtiny85_SD_new.zip i do not use playsample(), i use ISR(TIMER0_COMPA_vect),

I know, but you haven't posted the output.wav from ATtiny85_SD_new.

 

And yet in both cases the arithmetic used in play() to configure the timer interrupt is based on 11.264 MHz.  So how exactly did you arrive at the figures for prescaler and top for each type of wav?

 

Surely you noticed that the pitch of the output is nowhere near 500 Hz?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]