Skip to content

Commit fabfc85

Browse files
committed
Add analogin driver for CM3DS MPS2 target
This patch adds analogin driver for CM3DS MPS2 target. Signed-off-by: Hugues de Valon <[email protected]>
1 parent 985a2bb commit fabfc85

File tree

3 files changed

+155
-6
lines changed

3 files changed

+155
-6
lines changed
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2017 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/*
18+
* This HAL implementation uses the AD7490 analog-to-digital converter
19+
* available on the MPS2 Adapter for Arduino shields.
20+
*/
21+
22+
#include "analogin_api.h"
23+
#include "gpio_api.h"
24+
#include "spi_api.h"
25+
#include "mbed_error.h"
26+
#include "mbed_wait_api.h"
27+
#include "pinmap.h"
28+
29+
/*
30+
* There is only one AD7490 controller to read the analog pins in both shields.
31+
* The AD7490 documentation (AD7490.pdf, page 12) tells us the right control
32+
* register to send.
33+
*/
34+
35+
/* Output conversion is straight binary */
36+
#define CODING (1 << 0)
37+
/* Analog input range from 0 to REF_IN volts */
38+
#define RANGE (1 << 1)
39+
/* DOUT line state, weakly driven or three-state */
40+
#define WEAK_TRI (1 << 2)
41+
/* Access to the shadow register */
42+
#define SHADOW (1 << 3)
43+
/* Normal operation power mode */
44+
#define PM0 (1 << 4)
45+
/* Normal operation power mode */
46+
#define PM1 (1 << 5)
47+
/* Write control register */
48+
#define WRITE (1 << 11)
49+
#define NORMAL_CONTROL_REGISTER (CODING | RANGE | PM0 | PM1 | WRITE)
50+
/* The ADC will ignore the write of this control register */
51+
#define NO_WRITE_CONTROL_REGISTER 0x000
52+
/* Bit position of the channel number in the control register */
53+
#define CHANNEL_NUMBER_POSITION 6
54+
/* CS signal of the ADC needs to be put low during transfers */
55+
#define CS_LOW 0
56+
#define CS_HIGH 1
57+
/* The ADC expects a 16 bits word but only read the 12 most significant bits */
58+
#define USELESS_ADC_BITS 4
59+
/* The ADC result is on the 12 least significant bits */
60+
#define OUTPUT_DATA_MASK 0xFFF
61+
/* The maximum value is the biggest value than can be coded on 12 bits */
62+
#define MAXIMUM_VALUE_12_BITS OUTPUT_DATA_MASK
63+
#define FRAME_16_BITS 16
64+
#define NO_POLARITY_NO_PHASE 0
65+
#define MASTER_MODE 0
66+
/* Maximal SPI frequency as written in the ADC documentation */
67+
#define MAXIMAL_SPI_FREQUENCY_HZ 12000000
68+
69+
/* The value of the peripheral constant linked with one analog pins is the
70+
* channel number of that pin on the ADC:
71+
* A0_0 is channel 0
72+
* ...
73+
* A0_5 is channel 5
74+
* A1_0 is channel 6
75+
* ...
76+
* A1_5 is channel 11
77+
*/
78+
static const PinMap PinMap_ADC[] = {
79+
{A0_0, ADC0_0, 0},
80+
{A0_1, ADC0_1, 0},
81+
{A0_2, ADC0_2, 0},
82+
{A0_3, ADC0_3, 0},
83+
{A0_4, ADC0_4, 0},
84+
{A0_5, ADC0_5, 0},
85+
{A1_0, ADC0_6, 0},
86+
{A1_1, ADC0_7, 0},
87+
{A1_2, ADC0_8, 0},
88+
{A1_3, ADC0_9, 0},
89+
{A1_4, ADC0_10, 0},
90+
{A1_5, ADC0_11, 0},
91+
{NC , NC, 0}
92+
};
93+
94+
/* mbed OS gpio_t structure for the CS pin linked to the ADC */
95+
static gpio_t adc_cs;
96+
97+
/* mbed OS spi_t structure to communicate with the ADC */
98+
static spi_t adc_spi;
99+
100+
void analogin_init(analogin_t *obj, PinName pin)
101+
{
102+
uint16_t control_register = NORMAL_CONTROL_REGISTER;
103+
uint32_t channel_number = pinmap_peripheral(pin, PinMap_ADC);
104+
105+
if (channel_number == (uint32_t)NC) {
106+
error("pin %d is not connected to the ADC", pin);
107+
}
108+
109+
/* Add the channel number to the control register */
110+
control_register |= (channel_number << CHANNEL_NUMBER_POSITION);
111+
/* Only the 12 first bits are taken into account */
112+
control_register <<= USELESS_ADC_BITS;
113+
obj->ctrl_register = control_register;
114+
115+
spi_init(&adc_spi, ADC_MOSI, ADC_MISO, ADC_SCLK, NC);
116+
spi_format(&adc_spi, FRAME_16_BITS, NO_POLARITY_NO_PHASE, MASTER_MODE);
117+
spi_frequency(&adc_spi, MAXIMAL_SPI_FREQUENCY_HZ);
118+
119+
gpio_init_out(&adc_cs, ADC_SSEL);
120+
}
121+
122+
uint16_t analogin_read_u16(analogin_t *obj)
123+
{
124+
uint16_t result;
125+
126+
/* Request conversion */
127+
gpio_write(&adc_cs, CS_LOW);
128+
/* Only write the control register, ignore the previous results */
129+
(void)spi_master_write(&adc_spi, obj->ctrl_register);
130+
gpio_write(&adc_cs, CS_HIGH);
131+
132+
/*
133+
* According to the documentation, t_QUIET (50 ns) time needs to pass before
134+
* accessing to the SPI bus again. We wait here 1 us as we can not wait a
135+
* shorter time than that.
136+
*/
137+
wait_us(1);
138+
139+
/* Read conversion result */
140+
gpio_write(&adc_cs, CS_LOW);
141+
/* Only read the results without writing the control register */
142+
result = spi_master_write(&adc_spi, NO_WRITE_CONTROL_REGISTER);
143+
gpio_write(&adc_cs, CS_HIGH);
144+
145+
return (result & OUTPUT_DATA_MASK);
146+
}
147+
148+
float analogin_read(analogin_t *obj)
149+
{
150+
uint16_t result = analogin_read_u16(obj);
151+
152+
return (result * (1. / MAXIMUM_VALUE_12_BITS));
153+
}

targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/objects.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,7 @@ struct clcd_s {
6666
};
6767

6868
struct analogin_s {
69-
ADCName adc;
70-
MPS2_SSP_TypeDef *adc_spi;
71-
PinName pin;
72-
uint32_t pin_number;
73-
__IO uint32_t address;
69+
uint16_t ctrl_register; /* Control bits with the channel identifier */
7470
};
7571

7672
#include "gpio_object.h"

targets/targets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1950,7 +1950,7 @@
19501950
"supported_toolchains": ["ARM", "GCC_ARM", "IAR"],
19511951
"extra_labels": ["ARM_SSG", "CM3DS_MPS2"],
19521952
"macros": ["CMSDK_CM3DS"],
1953-
"device_has": ["ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SPI", "RTC"],
1953+
"device_has": ["ANALOGIN", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SPI", "RTC"],
19541954
"release_versions": ["2", "5"]
19551955
},
19561956
"ARM_BEETLE_SOC": {

0 commit comments

Comments
 (0)