Skip to content

Commit 2dc46a8

Browse files
authored
board/teensy40: Add ADC support (#1458)
machine/teensy40: add ADC support
1 parent f3afc7b commit 2dc46a8

File tree

1 file changed

+176
-0
lines changed

1 file changed

+176
-0
lines changed

src/machine/machine_mimxrt1062.go

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,3 +883,179 @@ func (p Pin) getMuxMode(config PinConfig) uint32 {
883883
panic("machine: invalid pin mode")
884884
}
885885
}
886+
887+
// maximum ADC value for the currently configured resolution (used for scaling)
888+
var adcMaximum uint32
889+
890+
// InitADC is not used by this machine. Use `(ADC).Configure()`.
891+
func InitADC() {}
892+
893+
// Configure initializes the receiver's ADC peripheral and pin for analog input.
894+
func (a ADC) Configure(config ADCConfig) {
895+
// if not specified, use defaults: 10-bit resolution, 4 samples/conversion
896+
const (
897+
defaultResolution = uint32(10)
898+
defaultSamples = uint32(4)
899+
)
900+
901+
a.Pin.Configure(PinConfig{Mode: PinInputAnalog})
902+
903+
resolution, samples := config.Resolution, config.Samples
904+
if 0 == resolution {
905+
resolution = defaultResolution
906+
}
907+
if 0 == samples {
908+
samples = defaultSamples
909+
}
910+
if resolution > 12 {
911+
resolution = 12 // maximum resolution of 12 bits
912+
}
913+
adcMaximum = (uint32(1) << resolution) - 1
914+
915+
mode, average := a.mode(resolution, samples)
916+
917+
nxp.ADC1.CFG.Set(mode | nxp.ADC_CFG_ADHSC) // configure ADC1
918+
nxp.ADC2.CFG.Set(mode | nxp.ADC_CFG_ADHSC) // configure ADC2
919+
920+
// begin calibration
921+
nxp.ADC1.GC.Set(average | nxp.ADC_GC_CAL)
922+
nxp.ADC2.GC.Set(average | nxp.ADC_GC_CAL)
923+
924+
for a.isCalibrating() {
925+
} // wait for calibration
926+
}
927+
928+
// Get performs a single ADC conversion, returning a 16-bit unsigned integer.
929+
// The value returned will be scaled (uniformly distributed) if necessary so
930+
// that it is always in the range [0..65535], regardless of the ADC's configured
931+
// bit size (resolution).
932+
func (a ADC) Get() uint16 {
933+
if ch1, ch2, ok := a.Pin.getADCChannel(); ok {
934+
for a.isCalibrating() {
935+
} // wait for calibration
936+
var val uint32
937+
if noADCChannel != ch1 {
938+
nxp.ADC1.HC0.Set(uint32(ch1))
939+
for !nxp.ADC1.HS.HasBits(nxp.ADC_HS_COCO0) {
940+
}
941+
val = nxp.ADC1.R0.Get() & 0xFFFF
942+
} else {
943+
nxp.ADC2.HC0.Set(uint32(ch2))
944+
for !nxp.ADC2.HS.HasBits(nxp.ADC_HS_COCO0) {
945+
}
946+
val = nxp.ADC2.R0.Get() & 0xFFFF
947+
}
948+
// should never be zero, but just in case, use UINT16_MAX so that the scalar
949+
// gets factored out of the conversion result, leaving the original reading
950+
// to be returned unaltered/unscaled.
951+
if adcMaximum == 0 {
952+
adcMaximum = 0xFFFF
953+
}
954+
// scale up to a 16-bit value
955+
return uint16((val * 0xFFFF) / adcMaximum)
956+
}
957+
return 0
958+
}
959+
960+
// mode constructs bit masks for mode and average - used in ADC configuration
961+
// registers - from a given ADC bit size (resolution) and sample count.
962+
func (a ADC) mode(resolution, samples uint32) (mode, average uint32) {
963+
964+
// use asynchronous clock (ADACK) (0 = IPG, 1 = IPG/2, or 3 = ADACK)
965+
mode = (nxp.ADC_CFG_ADICLK_ADICLK_3 << nxp.ADC_CFG_ADICLK_Pos) & nxp.ADC_CFG_ADICLK_Msk
966+
967+
// input clock DIV2 (0 = DIV1, 1 = DIV2, 2 = DIV4, or 3 = DIV8)
968+
mode |= (nxp.ADC_CFG_ADIV_ADIV_1 << nxp.ADC_CFG_ADIV_Pos) & nxp.ADC_CFG_ADIV_Msk
969+
970+
switch resolution {
971+
case 8: // 8-bit conversion, sample period (ADC clocks) = 8
972+
mode |= (nxp.ADC_CFG_MODE_MODE_0 << nxp.ADC_CFG_MODE_Pos) & nxp.ADC_CFG_MODE_Msk
973+
mode |= (nxp.ADC_CFG_ADSTS_ADSTS_3 << nxp.ADC_CFG_ADSTS_Pos) & nxp.ADC_CFG_ADSTS_Msk
974+
975+
case 12: // 12-bit conversion, sample period (ADC clocks) = 24
976+
mode |= (nxp.ADC_CFG_MODE_MODE_2 << nxp.ADC_CFG_MODE_Pos) & nxp.ADC_CFG_MODE_Msk
977+
mode |= (nxp.ADC_CFG_ADSTS_ADSTS_3 << nxp.ADC_CFG_ADSTS_Pos) & nxp.ADC_CFG_ADSTS_Msk
978+
mode |= nxp.ADC_CFG_ADLSMP
979+
980+
default: // 10-bit conversion, sample period (ADC clocks) = 20
981+
mode |= (nxp.ADC_CFG_MODE_MODE_1 << nxp.ADC_CFG_MODE_Pos) & nxp.ADC_CFG_MODE_Msk
982+
mode |= (nxp.ADC_CFG_ADSTS_ADSTS_2 << nxp.ADC_CFG_ADSTS_Pos) & nxp.ADC_CFG_ADSTS_Msk
983+
mode |= nxp.ADC_CFG_ADLSMP
984+
}
985+
986+
if samples >= 4 {
987+
if samples >= 32 {
988+
// 32 samples averaged
989+
mode |= (nxp.ADC_CFG_AVGS_AVGS_3 << nxp.ADC_CFG_AVGS_Pos) & nxp.ADC_CFG_AVGS_Msk
990+
} else if samples >= 16 {
991+
// 16 samples averaged
992+
mode |= (nxp.ADC_CFG_AVGS_AVGS_2 << nxp.ADC_CFG_AVGS_Pos) & nxp.ADC_CFG_AVGS_Msk
993+
} else if samples >= 8 {
994+
// 8 samples averaged
995+
mode |= (nxp.ADC_CFG_AVGS_AVGS_1 << nxp.ADC_CFG_AVGS_Pos) & nxp.ADC_CFG_AVGS_Msk
996+
} else {
997+
// 4 samples averaged
998+
mode |= (nxp.ADC_CFG_AVGS_AVGS_0 << nxp.ADC_CFG_AVGS_Pos) & nxp.ADC_CFG_AVGS_Msk
999+
}
1000+
average = nxp.ADC_GC_AVGE
1001+
}
1002+
1003+
return mode, average
1004+
}
1005+
1006+
// isCalibrating returns true if and only if either one (or both) of ADC1 and
1007+
// ADC2 have their calibrating flags set. ADC reads must wait until these flags
1008+
// are clear before attempting a conversion.
1009+
func (a ADC) isCalibrating() bool {
1010+
return nxp.ADC1.GC.HasBits(nxp.ADC_GC_CAL) || nxp.ADC2.GC.HasBits(nxp.ADC_GC_CAL)
1011+
}
1012+
1013+
const noADCChannel = uint8(0xFF)
1014+
1015+
// getADCChannel returns the input channel for ADC1/ADC2 of the receiver Pin p.
1016+
func (p Pin) getADCChannel() (adc1, adc2 uint8, ok bool) {
1017+
switch p {
1018+
case PA12: // [AD_B0_12]: ADC1_IN1 ~
1019+
return 1, noADCChannel, true
1020+
case PA13: // [AD_B0_13]: ADC1_IN2 ~
1021+
return 2, noADCChannel, true
1022+
case PA14: // [AD_B0_14]: ADC1_IN3 ~
1023+
return 3, noADCChannel, true
1024+
case PA15: // [AD_B0_15]: ADC1_IN4 ~
1025+
return 4, noADCChannel, true
1026+
case PA16: // [AD_B1_00]: ADC1_IN5 ADC2_IN5
1027+
return 5, 5, true
1028+
case PA17: // [AD_B1_01]: ADC1_IN6 ADC2_IN6
1029+
return 6, 6, true
1030+
case PA18: // [AD_B1_02]: ADC1_IN7 ADC2_IN7
1031+
return 7, 7, true
1032+
case PA19: // [AD_B1_03]: ADC1_IN8 ADC2_IN8
1033+
return 8, 8, true
1034+
case PA20: // [AD_B1_04]: ADC1_IN9 ADC2_IN9
1035+
return 9, 9, true
1036+
case PA21: // [AD_B1_05]: ADC1_IN10 ADC2_IN10
1037+
return 10, 10, true
1038+
case PA22: // [AD_B1_06]: ADC1_IN11 ADC2_IN11
1039+
return 11, 11, true
1040+
case PA23: // [AD_B1_07]: ADC1_IN12 ADC2_IN12
1041+
return 12, 12, true
1042+
case PA24: // [AD_B1_08]: ADC1_IN13 ADC2_IN13
1043+
return 13, 13, true
1044+
case PA25: // [AD_B1_09]: ADC1_IN14 ADC2_IN14
1045+
return 14, 14, true
1046+
case PA26: // [AD_B1_10]: ADC1_IN15 ADC2_IN15
1047+
return 15, 15, true
1048+
case PA27: // [AD_B1_11]: ADC1_IN0 ADC2_IN0
1049+
return 16, 16, true
1050+
case PA28: // [AD_B1_12]: ~ ADC2_IN1
1051+
return noADCChannel, 1, true
1052+
case PA29: // [AD_B1_13]: ~ ADC2_IN2
1053+
return noADCChannel, 2, true
1054+
case PA30: // [AD_B1_14]: ~ ADC2_IN3
1055+
return noADCChannel, 3, true
1056+
case PA31: // [AD_B1_15]: ~ ADC2_IN4
1057+
return noADCChannel, 4, true
1058+
default:
1059+
return noADCChannel, noADCChannel, false
1060+
}
1061+
}

0 commit comments

Comments
 (0)