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 {
|
||||
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"
|
||||
|
|
|
@ -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": {
|
||||
|
|
Loading…
Reference in New Issue