/* 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 #define BufferCount 4 #define TRUE 1 #define FALSE 0 // 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 char volatile BufferFull[BufferCount]; // Set this flag to true when it's time for the output thread to quit volatile char StopSending = FALSE; volatile int BuffersRead = 0; // How many buffers did we read from the file? // Forward declaration of the output function so we can launch it void OutputDataThread(void *par); #define 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) { int i; // Set up the SD card reader sd_mount(DO, CLK, DI, CS); // Mount SD card FILE* fp; //Generate the file data a clock for the ClearPath motor for(i=0; i<512; i++ ) { Buffer[0][i] = (i & 7) | ((i>>8)<<3); // write the low 4 bits of the loop index into one of our temp buffers } printi("Start Program.\n"); //Write data to SD memory fp = fopen("test.txt", "wb"); // Open a file for writing for(i=0;i<8;i++) // write 512 bytes per iteration to the SD file, for a total of 64kb { fwrite(Buffer[0], 1, 512, fp); } fclose(fp); //End writing data to the SD Memory printi("Begin send.\n"); // Initialize buffers (just mark them all as empty) for( int i=0; i 0 ) { BuffersRead++; // We just read another buffer - tell the sending thread there's more work to do // 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 ); putChar( 'X' ); // so we see partial read errors } 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 putChar( 'E' ); // so we see when it terminates 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? int buffersSent = 0; // How many buffers have we sent out? // We're going to output to pins 0, 1, 2, 3 const int PinMask = (1<<0) | (1<<1) | ( 1<<2) | (1<<3); const 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 or we still have data to send out while( (StopSending == FALSE) | (buffersSent < BuffersRead) ) { 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); } buffersSent++; 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; } OUTA = 0; // Clear the outputs before the thread quits (makes it easer to count pulses on a scope) }