Add analogin driver for CM3DS MPS2 target

This patch adds analogin driver for
CM3DS MPS2 target.

Signed-off-by: Hugues de Valon <hugues.devalon@arm.com>
pull/4557/head
Marc Moreno Berengue 2017-06-14 10:25:13 +01:00
parent 985a2bb01d
commit fabfc85d31
3 changed files with 155 additions and 6 deletions

View File

@ -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));
}

View File

@ -66,11 +66,7 @@ struct clcd_s {
}; };
struct analogin_s { struct analogin_s {
ADCName adc; uint16_t ctrl_register; /* Control bits with the channel identifier */
MPS2_SSP_TypeDef *adc_spi;
PinName pin;
uint32_t pin_number;
__IO uint32_t address;
}; };
#include "gpio_object.h" #include "gpio_object.h"

View File

@ -1950,7 +1950,7 @@
"supported_toolchains": ["ARM", "GCC_ARM", "IAR"], "supported_toolchains": ["ARM", "GCC_ARM", "IAR"],
"extra_labels": ["ARM_SSG", "CM3DS_MPS2"], "extra_labels": ["ARM_SSG", "CM3DS_MPS2"],
"macros": ["CMSDK_CM3DS"], "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"] "release_versions": ["2", "5"]
}, },
"ARM_BEETLE_SOC": { "ARM_BEETLE_SOC": {