/* SDTest.side Read data from an SD card, output it to pins at a specified rate */ #include "simpletools.h" // Include simpletools header const int DO = 22, CLK = 23, DI = 24, CS = 25;// SD card pins on Propeller BOE // use four SD buffers to cycle through = 2Kb total data - you can change this to anything from 2 or greater const int BufferCount = 4; // each buffer is 512 bytes char Buffer[BufferCount][512]; // these flags tell us if a buffer has been read from the SD card or not (volatile means another thread might change it) volatile bool BufferFull[BufferCount]; // Set this flag to true when it's time for the output thread to quit volatile bool StopSending = false; // Forward declaration of the output function so we can launch it void OutputDataThread(void *par); const int OutputStackSize = 40 + 32; // stack needs to accommodate thread control structure (40) plus some room for locals and functions (32) static int OutputStack[OutputStackSize]; // allocate space for the output function stack // main function - this is the cog that reads SD data and fills buffers int main(void) { // Initialize buffers (just mark them all as empty) for( int i=0; i 0 ) { // yes - check to see if we got all we asked for if( readResult < 512 ) // did we not get a full 512 bytes? { // We didn't get all 512 bytes, so clear whatever we didn't overwrite memset( Buffer[bufferToRead] + readResult, 0, 512 - readResult ); } BufferFull[ bufferToRead ] = true; // mark this buffer as containing data bufferToRead = (bufferToRead+1) % BufferCount; // move on to the next buffer index, wrapping around to zero if necessary } else { // didn't read any bytes, so the file is finished; break out of this loop and end break; } } StopSending = true; // Tell the output thread we're done fclose(fp); // Close the file while( true ) { ; // do nothing forever when we're done } } // This thread waits for data in a buffer, then clocks it out at whatever the specified rate is void OutputDataThread(void *par) { int OutputRate = 53000; // 53khz output rate int OutputDelay = _clkfreq / OutputRate; // how long to delay between outputting bytes int bufferToSend = 0; // Which buffer are we sending data from? // We're going to output to pins 0, 1, 2, 3 int PinMask = (1<<0) | (1<<1) | ( 1<< 2) | (1<<3); int DataShift = 0; // How much to shift up the data we're reading in to send it to the right output pins DIRA |= PinMask; // set these pins to outputs DIRA |= (1 << 26); // ... and also pin 26 because that one has an LED connected to it // Record the current clock tick int clockTick = CNT; // the output loop - keep going until we're told not to while( StopSending == false ) { while( BufferFull[bufferToSend] == false ) { // re-record the clock tick value, in case it takes a while to get a buffer of data // this SHOULD only happen at the very beginning, but if anything ever goes wrong with // an SD read and it takes longer than expected, this will prevent the code from // locking up clockTick = CNT; } for( int i=0; i<512; i++ ) // loop through all the bytes in this buffer { int data = Buffer[bufferToSend][i] & 0x0F; // Only keep the bottom 4 bits (0b00001111 would work here too) // add however long we need to wait to the clock tick number clockTick += OutputDelay; // wait until that time arrives waitcnt( clockTick ); // Set the output pins by ANDing off whatever was there before, and ORing in the new bits OUTA = (OUTA & ~PinMask) | (data << DataShift); } if( bufferToSend == 0 ) { OUTA = OUTA ^ (1<<26); // this is just so we know it's still working - toggle an LED on the first buffer of each cycle } // we've consumed and send this buffer - mark it free so the reader thread will refill it BufferFull[bufferToSend] = false; // move on to the next buffer, wrapping around to zero if necessary bufferToSend = (bufferToSend+1) % BufferCount; } }