{{ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ Digital To Analog Converter Engine │ │ │ │ Author: Kwabena W. Agyeman │ │ Updated: 1/11/2010 │ │ Designed For: P8X32A │ │ │ │ Copyright (c) 2010 Kwabena W. Agyeman │ │ See end of file for terms of use. │ │ │ │ Driver Info: │ │ │ │ The DACEngine runs a stereo digital to analog converter driver in the next free cog on the propeller chip when called. │ │ │ │ The driver, is only guaranteed and tested to work at an 80Mhz system clock or higher. The driver is designed for the P8X32A │ │ so port B will not be operational. │ │ │ │ Nyamekye, │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ }} CON '' '' 100Ω 1µF DAC_Left_Pin = 08 '' ───┳─── Left Out '' │ '' 10nF '' │ ''  '' '' 100Ω 1µF DAC_Right_Pin = 09 '' ───┳─── Right Out '' │ '' 10nF '' │ ''  VAR word dataBlock[512] word callerPointer word callePointer byte stopedOrStarted byte signedOrUnsigned byte bitsPerSample byte numberOfChannels word leftVolume word rightVolume long sampleRate PUB getDataBlockAddress return @dataBlock PUB startPlayer '' 3 Stack Longs '' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ '' │ Starts/Unpauses the stereo DAC player. The player will begin at whatever point it stopped at before. │ '' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ stopedOrStarted := true PUB stopPlayer '' 3 Stack Longs '' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ '' │ Stops/pauses the stereo DAC. The player will remember whatever point it stopped at. │ '' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ stopedOrStarted := false PUB transferData '' 3 Stack Longs '' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ '' │ Helps reliably transfers data to the stero DAC to play. Throttles data transfer speed to that of data play speed. │ '' │ │ '' │ Returns address of next data buffer to transfer data to. Does not return until data buffer is ready for transfer. │ '' │ │ '' │ At 8 bits per sample using 1 channel each data buffer is composed of 512 bytes with 512 samples per transfer. │ '' │ │ '' │ At 8 bits per sample using 2 channels each data buffer is composed of 512 bytes with 256 samples per transfer. │ '' │ │ '' │ At 16 bits per sample using 1 channel each data buffer is composed of 256 words with 256 samples per transfer. │ '' │ │ '' │ At 16 bits per sample using 2 channels each data buffer is composed of 256 words with 128 samples per transfer. │ '' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ repeat while(callerPointer == callePointer) result := @dataBlock[256 & callerPointer] not callerPointer PUB clearData '' 3 Stack Longs '' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ '' │ Clears all data in all player data buffers. │ '' │ │ '' │ Helps prevent old data from being played when changing to a new data transfer source. │ '' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ bytefill(@dataBlock, ((not(signedOrUnsigned)) & $80), 1024) PUB changeLeftChannelVolume(newVolume) '' 4 Stack Longs '' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ '' │ Changes the volume of the left channel. (0 to 100) │ '' │ │ '' │ NewVolume - New volume to output samples at. Samples are scaled by this value. Zero mutes the channel. │ '' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ leftVolume := (((newVolume <# 100) #> 0) * constant(65536 / 100)) PUB changeRightChannelVolume(newVolume) '' 4 Stack Longs '' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ '' │ Changes the volume of the right channel. (0 to 100) │ '' │ │ '' │ NewVolume - New volume to output samples at. Samples are scaled by this value. Zero mutes the channel. │ '' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ rightVolume := (((newVolume <# 100) #> 0) * constant(65536 / 100)) PUB changeSampleSign(signed) '' 4 Stack Longs '' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ '' │ Changes whether samples are signed or not. │ '' │ │ '' │ Signed - True to make all samples be interpreted as signed. False to make all samples be interpreted as unsigned. │ '' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ signedOrUnsigned := signed PUB changeBitsPerSample(newWidth) '' 4 Stack Longs '' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ '' │ Changes the bits per sample, 8 bits or 16 bits. │ '' │ │ '' │ NewWidth - New bits per sample to output samples at. Samples are sized by this value. (8 or 16) │ '' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ bitsPerSample := (newWidth == 16) PUB changeNumberOfChannels(newNumber) '' 4 Stack Longs '' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ '' │ Changes the number of channels, 1 channel or 2 channels. │ '' │ │ '' │ When set to 1 channel mode the driver will output samples to both channels at once. │ '' │ │ '' │ When set to 2 channel mode the driver will output samples to both channels at simultaneously. │ '' │ │ '' │ NewNumber - New number of channels to output samples at. Samples are grouped by this value. (1 or 2) │ '' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ numberOfChannels := (newNumber == 2) PUB changeSampleRate(newRate) '' 4 Stack Longs '' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ '' │ Changes the sample rate. The stereo DAC supportes samples rates from 1HZ to 88.2KHZ. │ '' │ │ '' │ NewRate - New sample rate to out samples at. Samples are outputted at the frequency specified by this value. │ '' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ sampleRate := (clkfreq / ((newRate <# 88200) #> 1)) PUB DACEngine(newRate) '' 4 Stack longs '' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ '' │ Initializes the stereo digital to analog converter driver to run on a new cog. │ '' │ │ '' │ Default mode is 8 bits per sample with unsigned samples, 1 channel with muted volume, and playing stopped. │ '' │ │ '' │ Returns the new cog's ID on sucess or -1 on failure. │ '' │ │ '' │ NewRate - New sample rate to out samples at. Samples are outputted at the frequency specified by this value. │ '' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ changeSampleRate(newRate) dataBlockAddress := @dataBlock callePointerAddress := @callePointer stopedOrStartedAddress := @stopedOrStarted unsignedOrSignedAddress := @signedOrUnsigned bitsPerSampleAddress := @bitsPerSample numberOfChannelsAddress := @NumberOfChannels leftVolumeAddress := @leftVolume rightVolumeAddress := @rightVolume return cognew(@initialization, @sampleRate) DAT ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ' Stereo Digital To Analog Converter Driver ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// org ' //////////////////////Initialization///////////////////////////////////////////////////////////////////////////////////////// initialization mov ctra, #((DAC_Left_Pin <# 31) #> 0) ' Setup counter I/O pins. mov ctrb, #((DAC_Right_Pin <# 31) #> 0) ' movi ctra, #%0_00110_000 ' Setup counter modes to duty cycle mode. movi ctrb, #%0_00110_000 ' mov dira, outputMask ' Setup I/O pin directions. mov playerPointer, dataBlockAddress ' Setup data block pointer. rdlong timeCounter, par ' Setup timing. add timeCounter, cnt ' ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ' Player ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// outerLoop rdbyte buffer, numberOfChannelsAddress wz ' Setup player mode. muxz playerMode, #$1 ' rdbyte buffer, bitsPerSampleAddress wz ' muxz playerMode, #$2 ' test playerMode, #$1 wc ' Setup counter. mov counter, #128 ' if_c_or_z add counter, #128 ' if_c_and_z add counter, #256 ' ' //////////////////////Inner Loop///////////////////////////////////////////////////////////////////////////////////////////// innerLoop rdlong buffer, par ' Wait until next sample output period. waitcnt timeCounter, buffer ' rdbyte buffer, stopedOrStartedAddress ' If stopped loop continously. tjz buffer, #innerLoop ' movs multiplicand, #leftVolumeAddress ' Get and output value. call #decode ' mov frqa, sampleBuffer ' test playerMode, #1 wc ' Check number of channels. if_c mov frqb, frqa ' if_c jmp #nextLoop ' movs multiplicand, #rightVolumeAddress ' Get and output value. call #decode ' mov frqb, sampleBuffer ' nextLoop djnz counter, #innerLoop ' Loop. ' //////////////////////Outer Loop///////////////////////////////////////////////////////////////////////////////////////////// rdword buffer, callePointerAddress wz ' Switch data block pointer. if_z neg buffer, #1 ' if_nz mov buffer, #0 ' wrword buffer, callePointerAddress ' if_nz mov playerPointer, dataBlockAddress ' Setup data block pointer. jmp #outerLoop ' Loop. ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ' Decode Value ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// decode test playerMode, #$2 wc ' Read data depending on size. if_c rdbyte multiplyBuffer, playerPointer ' if_c add playerPointer, #1 ' if_nc rdword multiplyBuffer, playerPointer ' if_nc add playerPointer, #2 ' rdbyte buffer, unsignedOrSignedAddress wz ' Modify data depending on sign and size. if_z_and_c sub multiplyBuffer, #$80 ' if_c shl multiplyBuffer, #24 ' if_c sar multiplyBuffer, #16 ' if_z_and_nc sub multiplyBuffer, wordAdjust ' if_nc shl multiplyBuffer, #16 ' if_nc sar multiplyBuffer, #16 ' multiplicand rdword multiplyCounter, 0 ' Setup inputs. mov sampleBuffer, #0 ' abs multiplyBuffer, multiplyBuffer wc ' Backup sign. rcr sampleBuffer, #1 wz, nr ' multiplyLoop shr multiplyCounter, #1 wc ' Preform multiplication. if_c add sampleBuffer, multiplyBuffer ' shl multiplyBuffer, #1 wc ' tjnz multiplyCounter, #multiplyLoop ' negnz sampleBuffer, sampleBuffer ' Restore sign. add sampleBuffer, longAdjust ' Center output value. decode_ret ret ' Return. ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ' Data ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// wordAdjust long $8000 ' Edits word signed value. longAdjust long $80000000 ' Edits long unsigend value. ' //////////////////////Pin Masks////////////////////////////////////////////////////////////////////////////////////////////// outputMask long ((|<((DAC_Left_Pin <# 31) #> 0)) | (|<((DAC_Right_Pin <# 31) #> 0))) ' DAC Outputs. ' //////////////////////Addresses////////////////////////////////////////////////////////////////////////////////////////////// dataBlockAddress long 0 callePointerAddress long 0 stopedOrStartedAddress long 0 unsignedOrSignedAddress long 0 bitsPerSampleAddress long 0 numberOfChannelsAddress long 0 leftVolumeAddress long 0 rightVolumeAddress long 0 ' //////////////////////Run Time Variables///////////////////////////////////////////////////////////////////////////////////// buffer res 1 counter res 1 playerPointer res 1 playerMode res 1 sampleBuffer res 1 timeCounter res 1 multiplyBuffer res 1 multiplyCounter res 1 ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// fit 496 {{ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ TERMS OF USE: MIT License │ ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ │files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ │modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the │ │Software is furnished to do so, subject to the following conditions: │ │ │ │The above copyright notice and this permission notice shall be included in all copies or substantial portions of the │ │Software. │ │ │ │THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ │WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ │COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ │ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ }}