samd/adc_dac: Implememt adc.read_timed() and dac.write_timed().#9624
Conversation
727362d to
643c4c3
Compare
ffb6c55 to
96495ce
Compare
7a4b1f4 to
5ea4230
Compare
cac0bfb to
c57be77
Compare
c57be77 to
1ef862d
Compare
1cf0992 to
b829186
Compare
|
Just a conflict resolved after rebase. |
|
@dpgeorge You mentioned about this PR that you would have to consider a proper API for that ADC/DAC timed feature. I guess you did not have time and it got lost under all other requests you have. The actual PR's API is close to that of the STM32 port. |
529c1c8 to
bcd688a
Compare
|
Re-based and Re-tested. Still fine. |
bcd688a to
d76cf5a
Compare
|
Code size report: |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #9624 +/- ##
=======================================
Coverage 98.46% 98.46%
=======================================
Files 176 176
Lines 22811 22811
=======================================
Hits 22460 22460
Misses 351 351 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
1cf57d7 to
d59e450
Compare
4070f1d to
3fea431
Compare
Actually TC4 and TC5 are combined. The datasheet seems to be wrong. Otherwise, TC3 could not be used.
But with a 1000µs resolution. |
No, stm32's |
2e2d257 to
d31eaff
Compare
|
I tested this again on ADAFRUIT_ITSYBITSY_M0_EXPRESS, using ADC and DAC separately. I used Testing I think this is very close to being merged now. @robert-hh is there anything more you want to do? Some of the commits need to be squashed. Feel free to do that yourself, or I can do it during merge. |
|
@dpgeorge Thank you for the review. I incorporated the suggested changes. Reducing the number of commits seems difficult. I dropped two, and some could be combined, like two that add the callback option. |
OK, we can leave them mostly as they are. The main thing I saw was the change to |
That is commit |
Used for allocation of DMA channels. It will be needed for planned modules and methods like adc_timed(), dac_timed(), I2S. It includes management code for DMA IRQ handlers, similar to what was made for Sercom. Signed-off-by: robert-hh <[email protected]>
These functions are use to allocate, free and configure a set of TC counter instances. The SAMxx MCU have between 3 to 5 (SAMD21) and 4 to 8 (SAMD51) TC instances. Two of them are used for the µs counter, the remaining 1 - 6 instances are administered here for use by various functions, like timed DMA transfers. Signed-off-by: robert-hh <[email protected]>
Used as:
dac.write_timed(data, freq [, count])
dac.deinit()
Working range for dac_timed():
SAMD21: 1 Hz - 100 kHz (1 MHz clock, 10 bit)
SAMD51: 1 Hz - ~500 kHz (8 MHz clock, 12 bit)
The buffer has to be a byte array or a halfword array,
and the data is sent once.
The default for count is 1. If set to a value > 0, the data will be
transmitted count times. If set to 0 or < 0, the date will be
transmitted until deliberately stopped. The playback
can be stopped with dac.deinit().
dac.deinit() just releases the timer and DMA channel needed by
dac_timed(). The DAC object itself does not have to be released.
Signed-off-by: robert-hh <[email protected]>
Used as:
adc.read_timed(buffer, freq)
Buffer must be preallocated. The size determines the number of 16 bit
words to be read. The numeric range of the results is that of the raw
ADC. The call returns immediately, and the data transfer is done by DMA.
The caller must wait sufficiently long until the data is sampled
and can be noticed by a callback. No internal checks are made for
a too-high freq value.
Read speeds depends on Average and bit length setting:
SAMD21: Max. 350kS/s (8 bit, Average 1)
SAMD51: Max. 1 MS/s (8 bit, Average 1)
Signed-off-by: robert-hh <[email protected]>
The callback is called when a dac_timed() sequence finishes. It will be reset with callback=None or omitting the callback option in the constructor. Side change: Set the clock freq. to 48Mhz. Signed-off-by: robert-hh <[email protected]>
Enabling a callback that will be called when a adc.read_timed_into() run is finished. That's especially useful with slow sampling rates and/or many samples, avoiding to guess the sampling time. Raise an error is adc.read_u16() is called while a read_timed_into() is active. Other ADC changes: - SAMD51: use ADC1 if both ADC1 and ADC0 are available at a Pin. Signed-off-by: robert-hh <[email protected]>
These return True, while a timed action is ongoing. Side change: Reorder some code in machine_dac.c and do not reset DAC twice. Signed-off-by: robert-hh <[email protected]>
Signed-off-by: robert-hh <[email protected]>
Since the two channels of a SAMD51 are not completely independent, dac.deinit() now clears both channels, and both channels have to be re-instantiated after a deinit(). Side change: - rearrange some code lines. Signed-off-by: robert-hh <[email protected]>
Both together require ~1.9k of flash space, including the DMA-manager and the TC-manager. adc.read_timed() uses ~700 bytes, dac.write_timed() ~600 bytes. Signed-off-by: robert-hh <[email protected]>
Fixes: - Leave no half-initialized device if init fails. - Fix dac_deinit_channel(). Perform deinit only for channels that had been initilized. Signed-off-by: robert-hh <[email protected]>
After machine.ADC has been moved to extmod/machine_adc.c. Adding adc.read_timed() and adc.busy() to extmod/machine_adc.c with a corresponding flag to enable them. ADC/DAC timed are by default enabled only at all SAMD51 devices and at SAMD21 devices with an external flash for the file system. Add class constants for the reference voltage source. As far as possible the STM32 names are used, except where they should match common board silkscreen labels. Signed-off-by: robert-hh <[email protected]>
When averaging is selected, the resolution is fixed to 12 bit. The configuration has to be changed to cater for the result shifts. Side change: Remove a duplicated code line in init(). Signed-off-by: robert-hh <[email protected]>
|
Thanks @robert-hh for keeping this PR alive for so long, and updating it to latest master. |
|
Thank you very much for merging. |
@dpgeorge As requested, this is the separate PR for ADC-timed and DAC-timed. Below
is a short documentation.
ADC Constructor:
ADC(Pin, *, average=16, bits=12, vref=3, callback=None)
The callback keyword option is used for timed ADC sampling. The callback is executed when all data has been sampled.
ADC Methods:
adc.read_u16()
Read single value from the Analog Pin using the bits and average setting from the constructors.
adc.read_timed(data, freq)
Read adc values into the data buffer at a supplied frequency. The buffer must be pre-allocated. Values are stored as 16 bit quantities in the binary range given by the bits option. If bits=12, the value range is 0-4095.
The voltage range is defined by the vref option.
If in the constructor a callback was defined, it will be called after all data has been read. Alternatively, the method busy() can be used to tell, if the capture has finished.
adc.busy()
busy() returns
Truewhile the data acquisition using read_timed() is ongoing,Falseotherwise.adc.deinit()
Deinitialize as ADC object and release the resources used by it, especially the ADC channel and the timer used for read_timed().
DAC Constructor
DAC(id, *, vref=3, callback=None)
The resolution of the DAC is 12 bit for SAMD51 and 10 bit for SAMD21. SAMD21 devices have 1 DAC channel at GPIO PA02, accepting only 0 as id. SAMD51 devices have 2 DAC channels at GPIO PA02 and PA05 with values 0 and 1 for the id.
DAC Methods
dac.write(value)
Write a single value to the selected DAC output. The value range is 0-1023 for SAMD21 and 0-4095 for SAMD51. The voltage range depends on the vref setting.
dac.write_timed(data, freq [, count=1])
The call to dac_timed() allows to output a series of analogue values at a given rate. data must be a buffer with 16 bit values in the range of the DAC (10 bit of 12 bit). freq may have a range of 1Hz to ~200kHz for SAMD21 and 1 Hz to ~500kHz for SAMD51. The optional argument count specifies,
how often data output will be repeated. The range is 1 - 2**32. If count == 0, the data output will be repeated until stopped by a call to deinit(). If the data has been output count times, a callback will
be called, if given.
dac.busy()
Tells, whether a dac.write_timed() activity is ongoing. It returns
Trueif yes,Falseotherwise.dac.deinit()
Deinitialize the DAC and release the resources used by it, especially the DMA channel and the Timer. On most SAMD21 boards, there is just one timer available for dac.write_timed() and adc.read_timed_into(). So they cannot run both at the same time, and releasing the timer may be important. The DAC driver consumes a substantial amount of current. Calling deinit()
will reduce that as well.