diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/analogin_api.c b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/analogin_api.c new file mode 100644 index 0000000000..09028abdb1 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/analogin_api.c @@ -0,0 +1,153 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This HAL implementation uses the AD7490 analog-to-digital converter + * available on the MPS2 Adapter for Arduino shields. + */ + +#include "analogin_api.h" +#include "gpio_api.h" +#include "spi_api.h" +#include "mbed_error.h" +#include "mbed_wait_api.h" +#include "pinmap.h" + +/* + * There is only one AD7490 controller to read the analog pins in both shields. + * The AD7490 documentation (AD7490.pdf, page 12) tells us the right control + * register to send. + */ + +/* Output conversion is straight binary */ +#define CODING (1 << 0) +/* Analog input range from 0 to REF_IN volts */ +#define RANGE (1 << 1) +/* DOUT line state, weakly driven or three-state */ +#define WEAK_TRI (1 << 2) +/* Access to the shadow register */ +#define SHADOW (1 << 3) +/* Normal operation power mode */ +#define PM0 (1 << 4) +/* Normal operation power mode */ +#define PM1 (1 << 5) +/* Write control register */ +#define WRITE (1 << 11) +#define NORMAL_CONTROL_REGISTER (CODING | RANGE | PM0 | PM1 | WRITE) +/* The ADC will ignore the write of this control register */ +#define NO_WRITE_CONTROL_REGISTER 0x000 +/* Bit position of the channel number in the control register */ +#define CHANNEL_NUMBER_POSITION 6 +/* CS signal of the ADC needs to be put low during transfers */ +#define CS_LOW 0 +#define CS_HIGH 1 +/* The ADC expects a 16 bits word but only read the 12 most significant bits */ +#define USELESS_ADC_BITS 4 +/* The ADC result is on the 12 least significant bits */ +#define OUTPUT_DATA_MASK 0xFFF +/* The maximum value is the biggest value than can be coded on 12 bits */ +#define MAXIMUM_VALUE_12_BITS OUTPUT_DATA_MASK +#define FRAME_16_BITS 16 +#define NO_POLARITY_NO_PHASE 0 +#define MASTER_MODE 0 +/* Maximal SPI frequency as written in the ADC documentation */ +#define MAXIMAL_SPI_FREQUENCY_HZ 12000000 + +/* The value of the peripheral constant linked with one analog pins is the + * channel number of that pin on the ADC: + * A0_0 is channel 0 + * ... + * A0_5 is channel 5 + * A1_0 is channel 6 + * ... + * A1_5 is channel 11 + */ +static const PinMap PinMap_ADC[] = { + {A0_0, ADC0_0, 0}, + {A0_1, ADC0_1, 0}, + {A0_2, ADC0_2, 0}, + {A0_3, ADC0_3, 0}, + {A0_4, ADC0_4, 0}, + {A0_5, ADC0_5, 0}, + {A1_0, ADC0_6, 0}, + {A1_1, ADC0_7, 0}, + {A1_2, ADC0_8, 0}, + {A1_3, ADC0_9, 0}, + {A1_4, ADC0_10, 0}, + {A1_5, ADC0_11, 0}, + {NC , NC, 0} +}; + +/* mbed OS gpio_t structure for the CS pin linked to the ADC */ +static gpio_t adc_cs; + +/* mbed OS spi_t structure to communicate with the ADC */ +static spi_t adc_spi; + +void analogin_init(analogin_t *obj, PinName pin) +{ + uint16_t control_register = NORMAL_CONTROL_REGISTER; + uint32_t channel_number = pinmap_peripheral(pin, PinMap_ADC); + + if (channel_number == (uint32_t)NC) { + error("pin %d is not connected to the ADC", pin); + } + + /* Add the channel number to the control register */ + control_register |= (channel_number << CHANNEL_NUMBER_POSITION); + /* Only the 12 first bits are taken into account */ + control_register <<= USELESS_ADC_BITS; + obj->ctrl_register = control_register; + + spi_init(&adc_spi, ADC_MOSI, ADC_MISO, ADC_SCLK, NC); + spi_format(&adc_spi, FRAME_16_BITS, NO_POLARITY_NO_PHASE, MASTER_MODE); + spi_frequency(&adc_spi, MAXIMAL_SPI_FREQUENCY_HZ); + + gpio_init_out(&adc_cs, ADC_SSEL); +} + +uint16_t analogin_read_u16(analogin_t *obj) +{ + uint16_t result; + + /* Request conversion */ + gpio_write(&adc_cs, CS_LOW); + /* Only write the control register, ignore the previous results */ + (void)spi_master_write(&adc_spi, obj->ctrl_register); + gpio_write(&adc_cs, CS_HIGH); + + /* + * According to the documentation, t_QUIET (50 ns) time needs to pass before + * accessing to the SPI bus again. We wait here 1 us as we can not wait a + * shorter time than that. + */ + wait_us(1); + + /* Read conversion result */ + gpio_write(&adc_cs, CS_LOW); + /* Only read the results without writing the control register */ + result = spi_master_write(&adc_spi, NO_WRITE_CONTROL_REGISTER); + gpio_write(&adc_cs, CS_HIGH); + + return (result & OUTPUT_DATA_MASK); +} + +float analogin_read(analogin_t *obj) +{ + uint16_t result = analogin_read_u16(obj); + + return (result * (1. / MAXIMUM_VALUE_12_BITS)); +} diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/objects.h b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/objects.h index d5fea381e3..f60746f463 100644 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/objects.h +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/objects.h @@ -66,11 +66,7 @@ struct clcd_s { }; struct analogin_s { - ADCName adc; - MPS2_SSP_TypeDef *adc_spi; - PinName pin; - uint32_t pin_number; - __IO uint32_t address; + uint16_t ctrl_register; /* Control bits with the channel identifier */ }; #include "gpio_object.h" diff --git a/targets/targets.json b/targets/targets.json index c97b9fd08c..2a1a80003b 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -1950,7 +1950,7 @@ "supported_toolchains": ["ARM", "GCC_ARM", "IAR"], "extra_labels": ["ARM_SSG", "CM3DS_MPS2"], "macros": ["CMSDK_CM3DS"], - "device_has": ["ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SPI", "RTC"], + "device_has": ["ANALOGIN", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SPI", "RTC"], "release_versions": ["2", "5"] }, "ARM_BEETLE_SOC": {