-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
samd/adc_dac: Implememt adc.read_timed() and dac.write_timed(). #9624
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?
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 ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #9624 +/- ##
=======================================
Coverage 98.58% 98.58%
=======================================
Files 167 167
Lines 21590 21590
=======================================
Hits 21285 21285
Misses 305 305 ☔ View full report in Codecov by Sentry. |
1cf57d7
to
d59e450
Compare
4070f1d
to
3fea431
Compare
3fea431
to
caa3da7
Compare
059490e
to
19b80f2
Compare
19b80f2
to
8f3fc77
Compare
Is there hope of getting this merged into the mainline? Would be a useful addition - I tried cherry-picking the change set on top of #15890 but (unsurprisingly) there are quite a number of conflicts |
5efb48e
to
9637d30
Compare
@graeme-winter I keep this PR in sync with the master, but do not update it on the sever if there is no conflict. But I did just now. Since your PR #15890 changes machine_dac.c as well, there are a few minor conflicts. So if one of the PR is merged, the other has to be changed accordingly. |
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 <robert@hammelrath.com>
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 <robert@hammelrath.com>
Call: 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 <robert@hammelrath.com>
Call: 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 <robert@hammelrath.com>
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 <robert@hammelrath.com>
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 <robert@hammelrath.com>
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 <robert@hammelrath.com>
Signed-off-by: robert-hh <robert@hammelrath.com>
Signed-off-by: robert-hh <robert@hammelrath.com>
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 <robert@hammelrath.com>
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 <robert@hammelrath.com>
To leave no half-initialized device if init fails. Signed-off-by: robert-hh <robert@hammelrath.com>
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. Side changes: - Fix a type in pin_af.c, preventing to use a second ADC channel. - Remove a duplicate definition in mcu/samd21/mpconfigmcu.h. Signed-off-by: robert-hh <robert@hammelrath.com>
9637d30
to
a2d1d78
Compare
That had not been changed. Signed-off-by: robert-hh <robert@hammelrath.com>
@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
True
while the data acquisition using read_timed() is ongoing,False
otherwise.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
True
if yes,False
otherwise.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.