-
Notifications
You must be signed in to change notification settings - Fork 162
Sigma Delta ADC #2617
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Sigma Delta ADC #2617
Changes from 15 commits
f1a486e
d935dfd
d648826
32bd5c1
6bf5a4c
6dccf80
81933ba
a86a4ec
60bfc21
a2d7451
a19cefa
e0b3031
da03db9
e3d6728
dbf454f
4315522
0bc4ffc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,262 @@ | ||
module Clash.Cores.SigmaDeltaADC (sigmaDeltaADC) where | ||
|
||
import Clash.Prelude hiding (filter, truncate) | ||
import Clash.Sized.Internal.BitVector | ||
|
||
-- | Shared functions | ||
-- Function to remove the LSBs from a BitVector | ||
truncate | ||
:: (KnownNat n0, KnownNat n1) | ||
=> BitVector (n0 + n1) | ||
-- ^ entire bitvector | ||
-> BitVector n0 | ||
-- ^ bitvector without number of LSBs | ||
truncate input = output | ||
where | ||
(output, _) = split input | ||
|
||
-- | Remove the LSBs from the accumulator output when the accumulator is ready | ||
-- This is used for both the accumulator and the filter | ||
truncateAccum | ||
FloriaanB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
:: (KnownNat n0, KnownNat n1) | ||
=> BitVector n0 | ||
-- ^ The previous accum | ||
-> (BitVector (n0 + n1), Bool) | ||
-- ^ parts of the tuple | ||
-- | ||
-- 1. Accumulator output | ||
-- 2. Boolean for when the accumulator is ready | ||
-> (BitVector n0, BitVector n0) | ||
-- ^ parts of tuple | ||
-- | ||
-- 1. updated accum | ||
-- 2. output accum | ||
FloriaanB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
truncateAccum accum (sigma, rollover) | ||
| rollover = (sigma', accum) | ||
| otherwise = (accum, accum) | ||
where | ||
sigma' = truncate sigma | ||
|
||
-- |Accumulator | ||
FloriaanB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
-- The main function for the accumulator, | ||
-- all functions that start with accumulator are used for the accumulator | ||
FloriaanB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
accumulator | ||
:: ( HiddenClockResetEnable dom | ||
, KnownNat n0 | ||
, KnownNat n1 | ||
, KnownNat n2 | ||
, (n2) <= (n1 + n0)) | ||
=> SNat n0 | ||
-- ^ The ADC width | ||
-> SNat (n1 + n0) | ||
-- ^ The accumulator width | ||
-> Signal dom (BitVector n2) | ||
-- ^ The amount of ones from the input | ||
-> (Signal dom (BitVector n0) | ||
, Signal dom Bool) | ||
-- ^ Parts of the Tuple | ||
-- | ||
-- 1. The accumulator output | ||
-- 2. Accumulator ready going to the filter | ||
accumulator _ aw numOnes = (accum, rollover) | ||
where | ||
accum = mealyB truncateAccum 0 (sigma, rollover) | ||
(sigma, rollover) = accumulatorCounterT aw numOnes | ||
|
||
accumulatorCounterT | ||
:: ( HiddenClockResetEnable dom | ||
, KnownNat n0 | ||
, KnownNat n1 | ||
, n1 <= n0) | ||
=> SNat n0 | ||
-- ^ the accumulator width | ||
-> Signal dom (BitVector n1) | ||
-- ^ The amount of ones from the input | ||
-> ( Signal dom (BitVector n0) | ||
, Signal dom Bool) | ||
-- ^ Parts of the Tuple | ||
-- | ||
-- 1. The accumulator output | ||
-- 2. Accumulator ready going to the filter | ||
accumulatorCounterT _ numOnes = mealyB accumulatorCounter (0, False, 0, 0) numOnes | ||
|
||
-- | The counter for sigma, which counts counts the number of ones from | ||
-- the input and resets when count is equal to zero | ||
accumulatorCounter | ||
:: (KnownNat n0, KnownNat n1, n1 <= n0) | ||
=> ( BitVector (n0 + 1) | ||
, Bool | ||
, BitVector n1 | ||
, BitVector (n0 - n1 + 1)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's unclear to me what these type variables mean. |
||
-- ^ Parts of the Tuple | ||
-- | ||
-- 1. The previous sigma | ||
-- 2. bool for when sigma is ready | ||
-- 3. previous number of ones from the input | ||
-- 4. previous value of the main counter-> BitVector n1 | ||
-> BitVector n1 | ||
-- ^ number of ones from the input | ||
-> ( ( BitVector (n0 + 1) | ||
, Bool | ||
, BitVector n1 | ||
, BitVector (n0 - n1 + 1)) | ||
, ( BitVector n0 | ||
, Bool) | ||
) | ||
-- ^ Parts of the Tuple | ||
-- | ||
-- 1. The new sigma | ||
-- 2. bool for when sigma is ready | ||
-- 3. new number of ones from the input | ||
-- 4. new value of the main counter | ||
-- 5. The accumulator output | ||
-- 6. Accumulator ready going to the filter | ||
accumulatorCounter (sigma, rollover, numOnes, count) numOnes' = | ||
((newState, rollover', numOnes', count'), (resize sigma, rollover)) | ||
where | ||
count' = count + 1 | ||
rollover' = (count == 0) | ||
newState | ||
| rollover = resize numOnes | ||
| sigma /= maxBound = min (sigma + resize numOnes) (shiftR maxBound 1) | ||
| otherwise = maxBound | ||
|
||
-- | Box avaraging filter | ||
-- | All functions that start with filter are used for the box averaging filter | ||
filter | ||
:: (HiddenClockResetEnable dom, KnownNat n0, KnownNat n1) | ||
=> SNat n1 | ||
-- ^ Filter Depth | ||
-> Signal dom (BitVector n0) | ||
-- ^ The input of the filter, width is equal to the adc width | ||
-> Signal dom Bool | ||
-- ^ Boolean to show when the accumulator is ready | ||
-> ( Signal dom (BitVector n0) | ||
, Signal dom Bool) | ||
-- ^ Parts of the tuple | ||
-- 1. The filtered output | ||
-- 2. trigger when a new sample is ready | ||
filter fw dataIn accumRdy = (dataOut, resultValid) | ||
where | ||
(accumulate, latchResult, resultValid) = | ||
mealyB filterPipeline (False, False, False) (accumRdy, count) | ||
count = filterCount fw accumRdy | ||
accum = mealyB filterAccumulator 0 (count, dataIn, accumulate) | ||
dataOut = mealyB truncateAccum 0 (accum, latchResult) | ||
|
||
-- | The accumulator for the filter, it adds the input to accum when | ||
-- the sample from the accumulator is ready | ||
filterAccumulator | ||
:: (KnownNat n0, KnownNat n1) | ||
=> BitVector (n0 + n1) | ||
-- ^ previous count of the filter accumulator | ||
-> (BitVector n1, BitVector n0, Bool) | ||
-- ^ Parts of the Tuple: | ||
-- 1. The filter counter | ||
-- 2. Input data from a filter accumulator | ||
-- 3. boolean for when the sample from the filter accumulator is ready | ||
-> (BitVector (n0 + n1), BitVector (n0 + n1)) | ||
-- ^ Parts of the Tuple | ||
-- 1. the new count of the accumulator | ||
-- 2. the downsampled output of the filter and adc | ||
filterAccumulator accum (count, dataIn, accumulate) | ||
| count == 1 && accumulate = (extend dataIn, accum) | ||
| accumulate = (accum + extend dataIn, accum) | ||
| otherwise = (accum, accum) | ||
|
||
-- | FilterPipeline to sync all the signals | ||
-- contains 3 registers to determine when the filter needs to accumulate. | ||
-- this happens when the accumulator is ready | ||
filterPipeline | ||
:: (KnownNat n0) | ||
=> (Bool, Bool, Bool) | ||
-- ^ parts of the tuple | ||
-- | ||
-- 1. accum ready with 1 cycle of delay | ||
-- 2. accum ready with 2 cycles of delay | ||
-- 3. latch result with 1 cycle of delay | ||
-> (Bool, BitVector n0) | ||
-- ^ parts of tuple | ||
-- input of the mealy machine | ||
-- 1. accum ready | ||
-- 2. the main counter | ||
-> ( (Bool, Bool, Bool), | ||
(Bool, Bool, Bool)) | ||
-- ^ parts of the tuple | ||
-- | ||
-- 1,2,3. input for all the registers | ||
-- 4, boolean for when the filter need to accumulate | ||
-- 5. boolean for when the filter accumulator of ready | ||
-- 6. boolean for when the output for the adc is ready | ||
filterPipeline (accumRdyD1, accumRdyD2, latchResult) (accumRdy, count) = | ||
( (accumRdyD1', accumRdyD2', latchResult') | ||
, (accumulate, latchResult', latchResult)) | ||
where | ||
accumRdyD1' = accumRdy | ||
accumRdyD2' = accumRdyD1 | ||
accumulate = accumRdyD1 && not accumRdyD2 | ||
latchResult' = accumulate && (count == 1) | ||
|
||
-- | Count when the input sample is ready it counts till 2^(filterWidth) | ||
filterCount | ||
:: (HiddenClockResetEnable dom, KnownNat n0) | ||
=> SNat n0 | ||
-- ^ Filter width | ||
-> Signal dom Bool | ||
-- ^ Sample ready boolean | ||
-> Signal dom (BitVector n0) | ||
-- ^ Counter output | ||
filterCount _ accumRdy = output | ||
where | ||
output = regEn 0 accumRdy (output + 1) | ||
|
||
-- | Sigma Delta ADC configurable in the ADC width, OSR and filter depth | ||
-- | ||
-- | The frequency for the ADC is equal to | ||
-- clk / 2^((AccumulatorWidth - BitsPerCycle - 1) + FilterDepth), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add and export a utility function for this? |
||
-- where clk is the operating frequency of the ADC | ||
sigmaDeltaADC | ||
:: ( HiddenClockResetEnable dom | ||
, KnownNat n0 | ||
, KnownNat n1 | ||
, KnownNat n2 | ||
, KnownNat n3 | ||
, CLog 2 (n3 + 2) <= (n1 + n0) | ||
) | ||
=> SNat n0 | ||
-- ^ ADC width | ||
-> SNat (n0 + n1) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do I determine this number? |
||
-- ^ Accumulator width | ||
-- Has to be larger or equal to the ADC width, | ||
-- the OSR is equal to 2^(AccumulatorWidth - ADCwidth) | ||
-> SNat n2 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do I determine this number? |
||
-- ^ Filter depth | ||
-- The depth of the decimation filter, | ||
-- the downsampling rate is equal to 2^FilterDepth | ||
-> Signal dom (BitVector (n3 + 1)) | ||
-- ^ analog input from the comparator | ||
FloriaanB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
-- For the design either lvds or an external comparator can be used | ||
-- the input signal had to be connected to the positive input while | ||
-- the output from a low pass RC-network connects to the negative input. | ||
-- The input is a bitvector such that ddr or a deserialiser can be utilised | ||
-- to get more bits per clock cycle for an increased sampling frequency. | ||
FloriaanB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
-> ( Signal dom (BitVector (n3 + 1)) | ||
, Signal dom (BitVector n0) | ||
, Signal dom Bool | ||
) | ||
-- ^ parts of the tuple | ||
-- | ||
-- 1. feedback to the RC network: | ||
-- The R and C of the low pass network need to be chosen such that: | ||
-- RC inbetween 200 and 1000 x clk, where clk is the frequency of | ||
-- output | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this too, should be at module level or function level. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there an optimal value? if so, how do we choose it? |
||
-- | ||
-- 2. the digital output of the ADC | ||
-- | ||
-- 3. Trigger for when the output is ready | ||
sigmaDeltaADC adcw accumw filterw analogCmp = (delta, digitalOut, sampleRdy) | ||
where | ||
delta = register 0 analogCmp | ||
(accum, accumRdy) = accumulator adcw accumw numOnes | ||
(digitalOut, sampleRdy) = filter filterw accum accumRdy | ||
numOnes = pack <$> (popCountBV <$> delta) |
Uh oh!
There was an error while loading. Please reload this page.