blob: f04f5ce237026be34df7eb9f7be401949562a44f [file] [log] [blame]
Brian Silvermancabadaf2018-09-03 19:36:44 -07001#ifndef MOTORS_PERIPHERAL_ADC_DMA_H_
2#define MOTORS_PERIPHERAL_ADC_DMA_H_
3
Brian Silvermancabadaf2018-09-03 19:36:44 -07004#include <stdint.h>
5
Philipp Schrader790cb542023-07-05 21:06:52 -07006#include <array>
7
Brian Silvermancabadaf2018-09-03 19:36:44 -07008#include "motors/core/kinetis.h"
9#include "motors/peripheral/configuration.h"
10#include "motors/util.h"
11
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080012namespace frc971::teensy {
Brian Silvermancabadaf2018-09-03 19:36:44 -070013
14// This class manages configuring the hardware to automatically capture various
15// sensor values periodically with tight timing. Currently it's only 4 samples
16// on each of ADC0 and ADC1.
17// TODO(Brian): Capture the encoder value (and velocity?) too.
18//
19// Uses:
20// * Both PDBs
21// * Both ADCs
22// * ADC_RESULT_DMA_CHANNEL and ADC_RECONFIGURE_DMA_CHANNEL
23class AdcDmaSampler {
24 public:
25 static constexpr int kNumberAdcSamples = 4;
26
27 // Corresponding samples in adc0_samples and adc1_samples happen
28 // simultaneously. Second sample happens at the cycle boundary. Elements
29 // should include the appropriate ADCH and DIFF values.
Brian Silvermana1d84822018-09-15 17:18:49 -070030 AdcDmaSampler(int counts_per_cycle);
Brian Silvermancabadaf2018-09-03 19:36:44 -070031
32 // Must be called before Initialize().
33 void set_adc0_samples(
34 const ::std::array<uint32_t, kNumberAdcSamples> &adc0_samples);
35 void set_adc1_samples(
36 const ::std::array<uint32_t, kNumberAdcSamples> &adc1_samples);
37 // pdb_input is the trigger-in index for PDB0 to use the attached FTM. This
38 // FTM must be set to do trigger-outs on exactly two of its channels, which
39 // will be dedicated to this object. This FTM must also start counting at 0 at
40 // the beginning of each cycle and have MOD set to match one cycle time.
41 void set_pdb_input(int pdb_input) { pdb_input_ = pdb_input; }
42 // ftm_delays is pointers to the two FTM.SCn registers which are set up to do
43 // trigger-outs.
44 void set_ftm_delays(const ::std::array<volatile uint32_t *, 2> &ftm_delays) {
45 ftm_delays_ = ftm_delays;
46 }
47
48 AdcDmaSampler(const AdcDmaSampler &) = delete;
49 AdcDmaSampler &operator=(const AdcDmaSampler &) = delete;
50
51 void Initialize();
52
53 // Checks if the current cycle has finished reading out results.
54 // After this returns true, it is safe to read the results until Reset() is
55 // called.
56 bool CheckDone() {
57 const uint32_t mask = 1 << reconfigure_dma_channel(1);
58 if (!(DMA.INT & mask)) {
59 return false;
60 }
61 DmaMemoryBarrier();
62 DMA.INT = mask;
63 (void)DMA.INT;
64 return true;
65 }
66
67 // Must be called after CheckDone() returns true each time.
68 void Reset();
69
70 int16_t adc_result(int adc, int i) { return adc_results_[adc][i]; }
71
72 private:
73 void InitializePdbChannel(KINETIS_PDB_CHANNEL_t *channel);
74
75 static constexpr int result_dma_channel(int adc) {
76 if (adc == 0) {
77 return ADC_RESULT_DMA_CHANNEL0;
78 }
79 return ADC_RESULT_DMA_CHANNEL1;
80 }
81 static KINETIS_TCD_t *result_dma(int adc) {
82 return &DMA.TCD[result_dma_channel(adc)];
83 }
84
85 static constexpr int reconfigure_dma_channel(int adc) {
86 if (adc == 0) {
87 return ADC_RECONFIGURE_DMA_CHANNEL0;
88 }
89 return ADC_RECONFIGURE_DMA_CHANNEL1;
90 }
91 static KINETIS_TCD_t *reconfigure_dma(int adc) {
92 return &DMA.TCD[reconfigure_dma_channel(adc)];
93 }
94
95 static constexpr int encoder_value_dma_channel() {
96 return ENCODER_VALUE_DMA_CHANNEL;
97 }
98
Brian Silvermana1d84822018-09-15 17:18:49 -070099 const int counts_per_cycle_;
100
Brian Silvermancabadaf2018-09-03 19:36:44 -0700101 ::std::array<::std::array<volatile uint32_t, kNumberAdcSamples + 2>, 2>
102 adc_sc1s_{};
103 ::std::array<::std::array<volatile uint16_t, kNumberAdcSamples>, 2>
104 adc_results_{};
105
106 int pdb_input_ = 0xF;
107 ::std::array<volatile uint32_t *, 2> ftm_delays_{nullptr, nullptr};
108};
109
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800110} // namespace frc971::teensy
Brian Silvermancabadaf2018-09-03 19:36:44 -0700111
112#endif // MOTORS_PERIPHERAL_ADC_DMA_H_