|
| 1 | +/* |
| 2 | + * mbed Microcontroller Library |
| 3 | + * Copyright (c) 2017-2018 Future Electronics |
| 4 | + * |
| 5 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | + * you may not use this file except in compliance with the License. |
| 7 | + * You may obtain a copy of the License at |
| 8 | + * |
| 9 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | + * |
| 11 | + * Unless required by applicable law or agreed to in writing, software |
| 12 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | + * See the License for the specific language governing permissions and |
| 15 | + * limitations under the License. |
| 16 | + */ |
| 17 | + |
| 18 | +#include "device.h" |
| 19 | +#include "analogin_api.h" |
| 20 | +#include "cy_sar.h" |
| 21 | +#include "psoc6_utils.h" |
| 22 | +#include "mbed_assert.h" |
| 23 | +#include "mbed_error.h" |
| 24 | +#include "pinmap.h" |
| 25 | +#include "PeripheralPins.h" |
| 26 | +#include "platform/mbed_error.h" |
| 27 | + |
| 28 | +#if DEVICE_ANALOGIN |
| 29 | + |
| 30 | +const uint16_t ADC_MAX_VALUE = 0x0fff; |
| 31 | + |
| 32 | +const uint32_t SAR_BASE_CLOCK_HZ = 18000000; // 18 MHz or less |
| 33 | + |
| 34 | +/** Default SAR channel configuration. |
| 35 | + * Notice, that because dynamic SAR MUX switching is disabled, |
| 36 | + * per-channel MUX configuration is ignored, thus not configured here. |
| 37 | + */ |
| 38 | +#define DEFAULT_CHANNEL_CONFIG ( \ |
| 39 | + CY_SAR_CHAN_SINGLE_ENDED | \ |
| 40 | + CY_SAR_CHAN_AVG_ENABLE | \ |
| 41 | + CY_SAR_CHAN_SAMPLE_TIME_0 \ |
| 42 | +) |
| 43 | + |
| 44 | + |
| 45 | +/** Global SAR configuration data, modified as channels are configured. |
| 46 | + */ |
| 47 | +static cy_stc_sar_config_t sar_config = { |
| 48 | + .ctrl = CY_SAR_VREF_SEL_VDDA_DIV_2 | |
| 49 | + CY_SAR_NEG_SEL_VREF | |
| 50 | + CY_SAR_CTRL_COMP_DLY_12 | |
| 51 | + CY_SAR_COMP_PWR_50 | |
| 52 | + CY_SAR_SARSEQ_SWITCH_DISABLE, /**< Control register */ |
| 53 | + .sampleCtrl = CY_SAR_RIGHT_ALIGN | |
| 54 | + CY_SAR_SINGLE_ENDED_UNSIGNED | |
| 55 | + CY_SAR_AVG_CNT_16 | |
| 56 | + CY_SAR_AVG_MODE_SEQUENTIAL_FIXED | |
| 57 | + CY_SAR_TRIGGER_MODE_FW_ONLY, /**< Sample control register */ |
| 58 | + .sampleTime01 = (4uL << CY_SAR_SAMPLE_TIME0_SHIFT) | |
| 59 | + (4uL << CY_SAR_SAMPLE_TIME1_SHIFT), /**< Sample time in ADC clocks for ST0 and ST1 */ |
| 60 | + .sampleTime23 = (4uL << CY_SAR_SAMPLE_TIME2_SHIFT) | |
| 61 | + (4uL << CY_SAR_SAMPLE_TIME3_SHIFT), /**< Sample time in ADC clocks for ST2 and ST3 */ |
| 62 | + .rangeThres = 0, /**< Range detect threshold register for all channels (unused)*/ |
| 63 | + .rangeCond = 0, /**< Range detect mode for all channels (unused)*/ |
| 64 | + .chanEn = 0, /**< Enable bits for the channels */ |
| 65 | + .chanConfig = { /**< Channel configuration registers */ |
| 66 | + DEFAULT_CHANNEL_CONFIG, // chn 0 |
| 67 | + DEFAULT_CHANNEL_CONFIG, // chn 1 |
| 68 | + DEFAULT_CHANNEL_CONFIG, // chn 2 |
| 69 | + DEFAULT_CHANNEL_CONFIG, // chn 3 |
| 70 | + DEFAULT_CHANNEL_CONFIG, // chn 4 |
| 71 | + DEFAULT_CHANNEL_CONFIG, // chn 5 |
| 72 | + DEFAULT_CHANNEL_CONFIG, // chn 6 |
| 73 | + DEFAULT_CHANNEL_CONFIG, // chn 7 |
| 74 | + DEFAULT_CHANNEL_CONFIG, // chn 8 |
| 75 | + DEFAULT_CHANNEL_CONFIG, // chn 9 |
| 76 | + DEFAULT_CHANNEL_CONFIG, // chn 10 |
| 77 | + DEFAULT_CHANNEL_CONFIG, // chn 11 |
| 78 | + DEFAULT_CHANNEL_CONFIG, // chn 12 |
| 79 | + DEFAULT_CHANNEL_CONFIG, // chn 13 |
| 80 | + DEFAULT_CHANNEL_CONFIG, // chn 14 |
| 81 | + DEFAULT_CHANNEL_CONFIG, // chn 15 |
| 82 | + }, |
| 83 | + .intrMask = 0, /**< Interrupt enable mask */ |
| 84 | + .satIntrMask = 0, /**< Saturate interrupt mask register */ |
| 85 | + .rangeIntrMask = 0, /**< Range interrupt mask register */ |
| 86 | + .muxSwitch = 0, /**< SARMUX firmware switches to connect analog signals to SAR */ |
| 87 | + .muxSwitchSqCtrl = 0, /**< SARMUX Switch SAR sequencer control */ |
| 88 | + .configRouting = false, /**< Configure or ignore routing related registers (muxSwitch, muxSwitchSqCtrl) */ |
| 89 | + .vrefMvValue = 0, /**< Reference voltage in millivolts used in counts to volts conversion */ |
| 90 | +}; |
| 91 | + |
| 92 | +static bool sar_initialized = false; |
| 93 | + |
| 94 | + |
| 95 | +static void sar_init(analogin_t *obj) |
| 96 | +{ |
| 97 | + if (!sar_initialized) { |
| 98 | + uint32_t sar_clock_divider = CY_INVALID_DIVIDER; |
| 99 | + |
| 100 | + sar_initialized = true; |
| 101 | + // Allocate and setup clock. |
| 102 | + sar_clock_divider = cy_clk_allocate_divider(CY_SYSCLK_DIV_8_BIT); |
| 103 | + if (sar_clock_divider == CY_INVALID_DIVIDER) { |
| 104 | + error("SAR clock divider allocation failed."); |
| 105 | + return; |
| 106 | + } |
| 107 | + Cy_SysClk_PeriphSetDivider(CY_SYSCLK_DIV_8_BIT, |
| 108 | + sar_clock_divider, |
| 109 | + ((CY_CLK_PERICLK_FREQ_HZ + SAR_BASE_CLOCK_HZ / 2) / SAR_BASE_CLOCK_HZ) - 1); |
| 110 | + Cy_SysClk_PeriphEnableDivider(CY_SYSCLK_DIV_8_BIT, sar_clock_divider); |
| 111 | + Cy_SysClk_PeriphAssignDivider(obj->clock, CY_SYSCLK_DIV_8_BIT, sar_clock_divider); |
| 112 | + |
| 113 | + Cy_SAR_Init(obj->base, &sar_config); |
| 114 | + Cy_SAR_Enable(obj->base); |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +void analogin_init(analogin_t *obj, PinName pin) |
| 119 | +{ |
| 120 | + uint32_t sar = 0; |
| 121 | + uint32_t sar_function = 0; |
| 122 | + |
| 123 | + MBED_ASSERT(obj); |
| 124 | + MBED_ASSERT(pin != (PinName)NC); |
| 125 | + |
| 126 | + |
| 127 | + sar = pinmap_peripheral(pin, PinMap_ADC); |
| 128 | + if (sar != (uint32_t)NC) { |
| 129 | + if (cy_reserve_io_pin(pin)) { |
| 130 | + error("ANALOG IN pin reservation conflict."); |
| 131 | + } |
| 132 | + obj->base = (SAR_Type*)CY_PERIPHERAL_BASE(sar); |
| 133 | + obj->pin = pin; |
| 134 | + obj->channel_mask = 1 << CY_PIN(pin); |
| 135 | + |
| 136 | + // Configure clock. |
| 137 | + sar_function = pinmap_function(pin, PinMap_ADC); |
| 138 | + obj->clock = CY_PIN_CLOCK(sar_function); |
| 139 | + sar_init(obj); |
| 140 | + pin_function(pin, sar_function); |
| 141 | + } else { |
| 142 | + error("ANALOG IN pinout mismatch."); |
| 143 | + } |
| 144 | +} |
| 145 | + |
| 146 | +float analogin_read(analogin_t *obj) |
| 147 | +{ |
| 148 | + uint16_t result = analogin_read_u16(obj); |
| 149 | + |
| 150 | + return (float)result * (1.0 / ADC_MAX_VALUE); |
| 151 | +} |
| 152 | + |
| 153 | +uint16_t analogin_read_u16(analogin_t *obj) |
| 154 | +{ |
| 155 | + uint32_t result = 0; |
| 156 | + |
| 157 | + Cy_SAR_SetChanMask(obj->base, obj->channel_mask); |
| 158 | + Cy_SAR_SetAnalogSwitch(obj->base, CY_SAR_MUX_SWITCH0, obj->channel_mask, CY_SAR_SWITCH_CLOSE); |
| 159 | + Cy_SAR_StartConvert(obj->base, CY_SAR_START_CONVERT_SINGLE_SHOT); |
| 160 | + if (Cy_SAR_IsEndConversion(obj->base, CY_SAR_WAIT_FOR_RESULT) == CY_SAR_SUCCESS) { |
| 161 | + result = Cy_SAR_GetResult32(obj->base, CY_PIN(obj->pin)); |
| 162 | + } else { |
| 163 | + error("ANALOG IN: measurement failed!"); |
| 164 | + } |
| 165 | + Cy_SAR_SetAnalogSwitch(obj->base, CY_SAR_MUX_SWITCH0, obj->channel_mask, CY_SAR_SWITCH_OPEN); |
| 166 | + // We are running 16x oversampling extending results to 16 bits. |
| 167 | + return (uint16_t)(result); |
| 168 | +} |
| 169 | + |
| 170 | +#endif // DEVICE_ANALOGIN |
| 171 | + |
0 commit comments