mirror of https://github.com/ARMmbed/mbed-os.git
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
parent
985a2bb01d
commit
fabfc85d31
|
@ -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));
|
||||||
|
}
|
|
@ -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"
|
||||||
|
|
|
@ -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": {
|
||||||
|
|
Loading…
Reference in New Issue