5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
23 uint16_t adcValues
[NUM_ANALOGS
] __DMA
;
24 uint16_t rtcBatteryVoltage
;
26 #define ADC_CS_HIGH() (ADC_SPI_GPIO->BSRRL = ADC_SPI_PIN_CS)
27 #define ADC_CS_LOW() (ADC_SPI_GPIO->BSRRH = ADC_SPI_PIN_CS)
38 #define SPI_TX_VOLTAGE 9
41 #define RESETCMD 0x4000
42 #define MANUAL_MODE 0x1000 // manual mode channel 0
44 uint16_t SPIx_ReadWriteByte(uint16_t value
)
46 while (SPI_I2S_GetFlagStatus(ADC_SPI
, SPI_I2S_FLAG_TXE
) == RESET
);
47 SPI_I2S_SendData(ADC_SPI
, value
);
49 while (SPI_I2S_GetFlagStatus(ADC_SPI
, SPI_I2S_FLAG_RXNE
) == RESET
);
50 return SPI_I2S_ReceiveData(ADC_SPI
);
53 static void ADS7952_Init()
55 GPIO_InitTypeDef GPIO_InitStructure
;
56 SPI_InitTypeDef SPI_InitStructure
;
58 GPIO_InitStructure
.GPIO_Pin
= ADC_SPI_PIN_MISO
| ADC_SPI_PIN_SCK
| ADC_SPI_PIN_MOSI
;
59 GPIO_InitStructure
.GPIO_Speed
= GPIO_Speed_2MHz
;
60 GPIO_InitStructure
.GPIO_Mode
= GPIO_Mode_AF
;
61 GPIO_InitStructure
.GPIO_OType
= GPIO_OType_PP
;
62 GPIO_InitStructure
.GPIO_PuPd
= GPIO_PuPd_NOPULL
;
63 GPIO_Init(ADC_SPI_GPIO
, &GPIO_InitStructure
);
65 GPIO_InitStructure
.GPIO_Pin
= ADC_SPI_PIN_CS
;
66 GPIO_InitStructure
.GPIO_Mode
= GPIO_Mode_OUT
;
67 GPIO_InitStructure
.GPIO_OType
= GPIO_OType_PP
;
68 GPIO_InitStructure
.GPIO_Speed
= GPIO_Speed_2MHz
;
69 GPIO_InitStructure
.GPIO_PuPd
= GPIO_PuPd_NOPULL
;
70 GPIO_Init(ADC_SPI_GPIO
, &GPIO_InitStructure
);
72 GPIO_PinAFConfig(ADC_SPI_GPIO
, ADC_SPI_PinSource_SCK
, ADC_GPIO_AF
);
73 GPIO_PinAFConfig(ADC_SPI_GPIO
, ADC_SPI_PinSource_MISO
, ADC_GPIO_AF
);
74 GPIO_PinAFConfig(ADC_SPI_GPIO
, ADC_SPI_PinSource_MOSI
, ADC_GPIO_AF
);
76 SPI_I2S_DeInit(ADC_SPI
);
78 SPI_InitStructure
.SPI_Direction
= SPI_Direction_2Lines_FullDuplex
;
79 SPI_InitStructure
.SPI_Mode
= SPI_Mode_Master
;
80 SPI_InitStructure
.SPI_DataSize
= SPI_DataSize_16b
;
81 SPI_InitStructure
.SPI_CPOL
= SPI_CPOL_Low
;
82 SPI_InitStructure
.SPI_CPHA
= SPI_CPHA_1Edge
;
83 SPI_InitStructure
.SPI_NSS
= SPI_NSS_Soft
;
84 SPI_InitStructure
.SPI_BaudRatePrescaler
= SPI_BaudRatePrescaler_8
;
85 SPI_InitStructure
.SPI_FirstBit
= SPI_FirstBit_MSB
;
86 SPI_InitStructure
.SPI_CRCPolynomial
= 7;
87 SPI_Init(ADC_SPI
, &SPI_InitStructure
);
88 SPI_Cmd(ADC_SPI
, ENABLE
);
89 SPI_I2S_ITConfig(ADC_SPI
, SPI_I2S_IT_TXE
, DISABLE
);
90 SPI_I2S_ITConfig(ADC_SPI
, SPI_I2S_IT_RXNE
, DISABLE
);
95 SPIx_ReadWriteByte(RESETCMD
);
99 SPIx_ReadWriteByte(MANUAL_MODE
);
107 GPIO_InitTypeDef GPIO_InitStructure
;
108 GPIO_InitStructure
.GPIO_Pin
= ADC_GPIO_PIN_MOUSE1
| ADC_GPIO_PIN_MOUSE2
;
109 GPIO_InitStructure
.GPIO_Mode
= GPIO_Mode_AN
;
110 GPIO_InitStructure
.GPIO_Speed
= GPIO_Speed_2MHz
;
111 GPIO_InitStructure
.GPIO_OType
= GPIO_OType_PP
;
112 GPIO_InitStructure
.GPIO_PuPd
= GPIO_PuPd_NOPULL
;
113 GPIO_Init(ADC_GPIO_MOUSE
, &GPIO_InitStructure
);
115 ADC3
->CR1
= ADC_CR1_SCAN
;
116 ADC3
->CR2
= ADC_CR2_ADON
| ADC_CR2_DMA
| ADC_CR2_DDS
;
117 ADC3
->SQR1
= (2 - 1) << 20;
119 ADC3
->SQR3
= (ADC_CHANNEL_MOUSE1
<< 0) + (ADC_CHANNEL_MOUSE2
<< 5);
120 ADC3
->SMPR1
= (ADC_SAMPTIME
<< 0) + (ADC_SAMPTIME
<< 3) + (ADC_SAMPTIME
<< 6) + (ADC_SAMPTIME
<< 9) + (ADC_SAMPTIME
<< 12) + (ADC_SAMPTIME
<< 15) + (ADC_SAMPTIME
<< 18) + (ADC_SAMPTIME
<< 21) + (ADC_SAMPTIME
<< 24);
121 ADC3
->SMPR2
= (ADC_SAMPTIME
<< 0) + (ADC_SAMPTIME
<< 3) + (ADC_SAMPTIME
<< 6) + (ADC_SAMPTIME
<< 9) + (ADC_SAMPTIME
<< 12) + (ADC_SAMPTIME
<< 15) + (ADC_SAMPTIME
<< 18) + (ADC_SAMPTIME
<< 21) + (ADC_SAMPTIME
<< 24) + (ADC_SAMPTIME
<< 27);
124 // Enable the DMA channel here, DMA2 stream 1, channel 2
125 ADC_DMA_Stream
->CR
= DMA_SxCR_PL
| DMA_SxCR_CHSEL_1
| DMA_SxCR_MSIZE_0
| DMA_SxCR_PSIZE_0
| DMA_SxCR_MINC
;
126 ADC_DMA_Stream
->PAR
= CONVERT_PTR_UINT(&ADC3
->DR
);
127 ADC_DMA_Stream
->M0AR
= CONVERT_PTR_UINT(&adcValues
[MOUSE1
]);
128 ADC_DMA_Stream
->NDTR
= 2;
129 ADC_DMA_Stream
->FCR
= DMA_SxFCR_DMDIS
| DMA_SxFCR_FTH_0
;
131 ADC1
->CR1
= ADC_CR1_SCAN
;
132 ADC1
->CR2
= ADC_CR2_ADON
| ADC_CR2_DMA
| ADC_CR2_DDS
;
133 ADC1
->SQR1
= (1 - 1) << 20;
135 ADC1
->SQR3
= (ADC_Channel_Vbat
<< 0);
136 ADC1
->SMPR1
= (ADC_SAMPTIME
<< 0) + (ADC_SAMPTIME
<< 3) + (ADC_SAMPTIME
<< 6) + (ADC_SAMPTIME
<< 9) + (ADC_SAMPTIME
<< 12) + (ADC_SAMPTIME
<< 15) + (ADC_SAMPTIME
<< 18) + (ADC_SAMPTIME
<< 21) + (ADC_SAMPTIME
<< 24);
137 ADC1
->SMPR2
= (ADC_SAMPTIME
<< 0) + (ADC_SAMPTIME
<< 3) + (ADC_SAMPTIME
<< 6) + (ADC_SAMPTIME
<< 9) + (ADC_SAMPTIME
<< 12) + (ADC_SAMPTIME
<< 15) + (ADC_SAMPTIME
<< 18) + (ADC_SAMPTIME
<< 21) + (ADC_SAMPTIME
<< 24) + (ADC_SAMPTIME
<< 27);
140 uint16_t getRTCBatteryVoltage()
142 return (rtcBatteryVoltage
* 2 * ADC_VREF_PREC2
) / 2048;
145 const uint16_t adcCommands
[MOUSE1
+2] =
147 MANUAL_MODE
| (SPI_STICK1
<< 7),
148 MANUAL_MODE
| (SPI_STICK2
<< 7),
149 MANUAL_MODE
| (SPI_STICK3
<< 7),
150 MANUAL_MODE
| (SPI_STICK4
<< 7),
151 MANUAL_MODE
| (SPI_S1
<< 7),
152 MANUAL_MODE
| (SPI_6POS
<< 7),
153 MANUAL_MODE
| (SPI_S2
<< 7),
154 MANUAL_MODE
| (SPI_L1
<< 7),
155 MANUAL_MODE
| (SPI_L2
<< 7),
156 MANUAL_MODE
| (SPI_LS
<< 7),
157 MANUAL_MODE
| (SPI_RS
<< 7),
158 MANUAL_MODE
| (SPI_TX_VOLTAGE
<< 7),
159 MANUAL_MODE
| (0 << 7), // small joystick left/right
160 MANUAL_MODE
| (0 << 7) // small joystick up/down
163 void adcReadSPIDummy()
165 // A dummy command to get things started
166 // (because the sampled data is lagging behind for two command cycles)
169 SPIx_ReadWriteByte(adcCommands
[0]);
174 uint32_t adcReadNextSPIChannel(uint8_t index
)
178 // This delay is to allow charging of ADC input capacitor
179 // after the MUX changes from one channel to the other.
180 // It was determined experimentally. Biggest problem seems to be
181 // the cross-talk between A4:S1 and A5:MULTIPOS. Changing S1 for one extreme
182 // to the other resulted in A5 change of:
184 // delay value A5 change Time needed for adcRead()
185 // 1 16 0.154ms - 0.156ms
186 // 38 5 0.197ms - 0.199ms
187 // 62 0 0.225ms - 0.243ms
190 for (uint8_t i
= 0; i
< 4; i
++) {
193 // command is changed to the next index for the last two readings
194 // (because the sampled data is lagging behind for two command cycles)
195 uint16_t val
= (0x0fff & SPIx_ReadWriteByte(adcCommands
[(i
>1) ? index
+1 : index
]));
196 #if defined(JITTER_MEASURE)
197 if (JITTER_MEASURE_ACTIVE()) {
198 rawJitter
[index
].measure(val
);
209 void adcOnChipReadStart()
211 ADC_DMA_Stream
->CR
&= ~DMA_SxCR_EN
; // Disable DMA
212 ADC3
->SR
&= ~(uint32_t)(ADC_SR_EOC
| ADC_SR_STRT
| ADC_SR_OVR
);
213 ADC_DMA
->LIFCR
= DMA_LIFCR_CTCIF0
| DMA_LIFCR_CHTIF0
| DMA_LIFCR_CTEIF0
| DMA_LIFCR_CDMEIF0
| DMA_LIFCR_CFEIF0
; // Write ones to clear bits
214 ADC_DMA_Stream
->M0AR
= CONVERT_PTR_UINT(&adcValues
[MOUSE1
]);
215 ADC_DMA_Stream
->NDTR
= 2;
216 ADC_DMA_Stream
->CR
|= DMA_SxCR_EN
; // Enable DMA
217 ADC3
->CR2
|= (uint32_t)ADC_CR2_SWSTART
;
219 ADC1
->SR
&= ~(uint32_t)(ADC_SR_EOC
| ADC_SR_STRT
| ADC_SR_OVR
);
220 ADC1
->CR2
|= (uint32_t)ADC_CR2_SWSTART
;
223 bool adcOnChipReadFinished()
225 return (ADC_DMA
->LISR
& DMA_LISR_TCIF0
);
230 uint16_t temp
[NUM_ANALOGS
-MOUSE1
] = { 0 };
231 uint8_t noInternalReads
= 0;
233 adcOnChipReadStart();
236 for (uint32_t index
=0; index
<MOUSE1
; index
++) {
237 adcValues
[index
] = adcReadNextSPIChannel(index
);
238 if (noInternalReads
< 4 && adcOnChipReadFinished()) {
239 for (uint8_t x
=0; x
<NUM_ANALOGS
-MOUSE1
; x
++) {
240 uint16_t val
= adcValues
[MOUSE1
+x
];
241 #if defined(JITTER_MEASURE)
242 if (JITTER_MEASURE_ACTIVE()) {
243 rawJitter
[MOUSE1
+x
].measure(val
);
248 if (++noInternalReads
< 4) {
249 adcOnChipReadStart();
255 if (noInternalReads
!= 4) {
256 TRACE("Internal ADC problem: reads: %d", noInternalReads
);
260 for (uint8_t x
=0; x
<NUM_ANALOGS
-MOUSE1
; x
++) {
261 adcValues
[MOUSE1
+x
] = temp
[x
] >> 2;
264 if (isVBatBridgeEnabled()) {
265 rtcBatteryVoltage
= ADC1
->DR
;
270 const int8_t ana_direction
[NUM_ANALOGS
] = {1,-1,1,-1, -1,1,-1, -1,-1, -1,1, 0,0,0};
272 uint16_t getAnalogValue(uint8_t index
)
274 if (ana_direction
[index
] < 0)
275 return 4095 - adcValues
[index
];
277 return adcValues
[index
];
279 #endif // #if !defined(SIMU)