Paparazzi UAS v7.1_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
pmw3901.c
Go to the documentation of this file.
1/*
2 * Copyright (C) Tom van Dijk
3 *
4 * This file is part of paparazzi
5 *
6 * paparazzi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * paparazzi is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with paparazzi; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
30#include "pmw3901.h"
31
32#include "mcu_periph/sys_time.h"
33#include "mcu_periph/gpio.h"
34
35
36// Based on crazyflie-firmware
37#ifndef PMW3901_RAD_PER_PX
38#define PMW3901_RAD_PER_PX 0.002443389
39#endif
40
41// SPI divisor, to adjust the clock speed according to the PCLK
42// Don't exceed 2MHz
43#ifndef PMW3901_SPI_CDIV
44#define PMW3901_SPI_CDIV SPIDiv32
45#endif
46
47#define PMW3901_REG_MOTION 0x02
48#define PMW3901_REG_DELTA_X_L 0x03
49#define PMW3901_REG_DELTA_X_H 0x04
50#define PMW3901_REG_DELTA_Y_L 0x05
51#define PMW3901_REG_DELTA_Y_H 0x06
52
53
54// Blocking read/write functions
57
59
60 pmw->trans.output_buf[0] = addr & 0x7F; // MSB 0 => read
61 pmw->trans.output_length = 1;
62 pmw->trans.input_length = 0;
64 spi_blocking_transceive(pmw->periph, &pmw->trans, 0.5);
65
66 pmw->trans.output_buf[0] = 0;
67 pmw->trans.output_length = 1;
68 pmw->trans.input_length = 1;
70 spi_blocking_transceive(pmw->periph, &pmw->trans, 0.5);
71
73 return pmw->trans.input_buf[0];
74
75}
76
77static void writeRegister_blocking(struct pmw3901_t *pmw, uint8_t addr, uint8_t data) {
79
81
82 pmw->trans.output_buf[0] = addr | 0x80; // MSB 1 => write
83 pmw->trans.output_length = 1;
84 pmw->trans.input_length = 0;
86 spi_blocking_transceive(pmw->periph, &pmw->trans, 0.5);
87
88 pmw->trans.output_buf[0] = data;
89 pmw->trans.output_length = 1;
90 pmw->trans.input_length = 0;
92 spi_blocking_transceive(pmw->periph, &pmw->trans, 0.5);
95 sys_time_usleep(200);
96}
97
98// For PixArt firmware compatibility:
99#define writeRegister(_addr, _data) writeRegister_blocking(pmw, (_addr), (_data))
100#define readRegister(_addr) readRegister_blocking(pmw, (_addr))
101#define wait_ms(_ms) sys_time_usleep((_ms) * 1000)
102
103
104static void initializeSensor(struct pmw3901_t *pmw) {
105
107 wait_ms(1);
109 wait_ms(1);
111 wait_ms(1);
112
113 // Power on reset
114 writeRegister(0x3A, 0x5A);
115
116 wait_ms(5);
117
118 // Try to detect sensor before initializing
119 int tries = 0;
120 while (readRegister(0x00) != 0x49 && tries < 100) {
121 sys_time_usleep(50);
122 tries++;
123 }
124 readRegister(0x5F);
125
126 readRegister(0x02);
127 readRegister(0x03);
128 readRegister(0x04);
129 readRegister(0x05);
130 readRegister(0x06);
131 wait_ms(1);
132
133 writeRegister(0x7F, 0x00);
134 writeRegister(0x61, 0xAD);
135 writeRegister(0x7F, 0x03);
136 writeRegister(0x40, 0x00);
137 writeRegister(0x7F, 0x05);
138 writeRegister(0x41, 0xB3);
139 writeRegister(0x43, 0xF1);
140 writeRegister(0x45, 0x14);
141 writeRegister(0x5B, 0x32);
142 writeRegister(0x5F, 0x34);
143 writeRegister(0x7B, 0x08);
144 writeRegister(0x7F, 0x06);
145 writeRegister(0x44, 0x1B);
146 writeRegister(0x40, 0xBF);
147 writeRegister(0x4E, 0x3F);
148 writeRegister(0x7F, 0x08);
149 writeRegister(0x65, 0x20);
150 writeRegister(0x6A, 0x18);
151 writeRegister(0x7F, 0x09);
152 writeRegister(0x4F, 0xAF);
153 writeRegister(0x5F, 0x40);
154 writeRegister(0x48, 0x80);
155 writeRegister(0x49, 0x80);
156 writeRegister(0x57, 0x77);
157 writeRegister(0x60, 0x78);
158 writeRegister(0x61, 0x78);
159 writeRegister(0x62, 0x08);
160 writeRegister(0x63, 0x50);
161 writeRegister(0x7F, 0x0A);
162 writeRegister(0x45, 0x60);
163 writeRegister(0x7F, 0x00);
164 writeRegister(0x4D, 0x11);
165 writeRegister(0x55, 0x80);
166 writeRegister(0x74, 0x1F);
167 writeRegister(0x75, 0x1F);
168 writeRegister(0x4A, 0x78);
169 writeRegister(0x4B, 0x78);
170 writeRegister(0x44, 0x08);
171 writeRegister(0x45, 0x50);
172 writeRegister(0x64, 0xFF);
173 writeRegister(0x65, 0x1F);
174 writeRegister(0x7F, 0x14);
175 writeRegister(0x65, 0x60);
176 writeRegister(0x66, 0x08);
177 writeRegister(0x63, 0x78);
178 writeRegister(0x7F, 0x15);
179 writeRegister(0x48, 0x58);
180 writeRegister(0x7F, 0x07);
181 writeRegister(0x41, 0x0D);
182 writeRegister(0x43, 0x14);
183 writeRegister(0x4B, 0x0E);
184 writeRegister(0x45, 0x0F);
185 writeRegister(0x44, 0x42);
186 writeRegister(0x4C, 0x80);
187 writeRegister(0x7F, 0x10);
188 writeRegister(0x5B, 0x02);
189 writeRegister(0x7F, 0x07);
190 writeRegister(0x40, 0x41);
191 writeRegister(0x70, 0x00);
192
193 wait_ms(100);
194 writeRegister(0x32, 0x44);
195 writeRegister(0x7F, 0x07);
196 writeRegister(0x40, 0x40);
197 writeRegister(0x7F, 0x06);
198 writeRegister(0x62, 0xf0);
199 writeRegister(0x63, 0x00);
200 writeRegister(0x7F, 0x0D);
201 writeRegister(0x48, 0xC0);
202 writeRegister(0x6F, 0xd5);
203 writeRegister(0x7F, 0x00);
204 writeRegister(0x5B, 0xa0);
205 writeRegister(0x4E, 0xA8);
206 writeRegister(0x5A, 0x50);
207 writeRegister(0x40, 0x80);
208}
209
210
211static void pmw3901_thd(void* arg) {
212 struct pmw3901_t* pmw = (struct pmw3901_t*) arg;
213
214 while(true) {
215
216 pprz_bsem_wait(&pmw->bsem); // wait to be woken up by the AP thread
217
223
224 pmw->delta_x = (xh << 8) | xl;
225 pmw->delta_y = (yh << 8) | yl;
226 pmw->data_available = true;
227 }
228
229}
230
231
232void pmw3901_init(struct pmw3901_t *pmw, struct spi_periph *periph, uint8_t slave_idx) {
233 // Set up SPI peripheral and transaction
234 pmw->periph = periph;
235 pmw->trans.input_buf = pmw->spi_input_buf;
236 pmw->trans.output_buf = pmw->spi_output_buf;
237 pmw->trans.slave_idx = slave_idx;
238 pmw->trans.select = SPINoSelect;
240 pmw->trans.cpha = SPICphaEdge2;
241 pmw->trans.dss = SPIDss8bit;
244 pmw->trans.before_cb = NULL;
245 pmw->trans.after_cb = NULL;
247 // Initialize sensor registers
248 initializeSensor(pmw);
249 // Set up remaining fields
250 pmw->state = PMW3901_IDLE;
251 pmw->delta_x = 0;
252 pmw->delta_y = 0;
253 pmw->data_available = false;
255
256 pprz_bsem_init(&pmw->bsem, true);
257 pprz_thread_create(&pmw->thd_handle, 1024, "pmw3901", PPRZ_NORMAL_PRIO+1, pmw3901_thd, pmw);
258}
259
261 if (!pmw->data_available) return false;
262 *delta_x = pmw->delta_x;
263 *delta_y = pmw->delta_y;
264 pmw->data_available = false;
265 return true;
266}
void sys_time_usleep(uint32_t us)
sys_time_usleep(uint32_t us)
void pprz_bsem_init(pprz_bsem_t *bsem, bool taken)
int pprz_thread_create(pprz_thread_t *thread, size_t size, const char *name, uint8_t prio, void(*pf)(void *), void *arg)
Creates a new thread whose stack is dynamically allocated.
void pprz_bsem_wait(pprz_bsem_t *bsem)
#define PPRZ_NORMAL_PRIO
Some architecture independent helper functions for GPIOs.
enum SPIClockPolarity cpol
clock polarity control
Definition spi.h:151
enum SPIClockPhase cpha
clock phase control
Definition spi.h:152
enum SPISlaveSelect select
slave selection behavior
Definition spi.h:150
SPICallback before_cb
NULL or function called before the transaction.
Definition spi.h:156
SPICallback after_cb
NULL or function called after the transaction.
Definition spi.h:157
enum SPIDataSizeSelect dss
data transfer word size
Definition spi.h:153
volatile uint8_t * output_buf
pointer to transmit buffer for DMA
Definition spi.h:146
uint16_t input_length
number of data words to read
Definition spi.h:147
enum SPIClockDiv cdiv
prescaler of main clock to use as SPI clock
Definition spi.h:155
volatile uint8_t * input_buf
pointer to receive buffer for DMA
Definition spi.h:145
uint8_t slave_idx
slave id: SPI_SLAVE0 to SPI_SLAVE4
Definition spi.h:149
enum SPIBitOrder bitorder
MSB/LSB order.
Definition spi.h:154
uint16_t output_length
number of data words to write
Definition spi.h:148
enum SPITransactionStatus status
Definition spi.h:158
enum SPITransactionStatus spi_blocking_transceive(struct spi_periph *p, struct spi_transaction *t, float timeout)
Perform a spi transaction (blocking).
Definition spi.c:169
void spi_slave_unselect(uint8_t slave)
spi_slave_unselect() function
Definition spi_arch.c:644
void spi_slave_select(uint8_t slave)
spi_slave_select() function
Definition spi_arch.c:582
@ SPICphaEdge2
CPHA = 1.
Definition spi.h:71
@ SPITransDone
Definition spi.h:97
@ SPICpolIdleHigh
CPOL = 1.
Definition spi.h:80
@ SPINoSelect
slave is not selected nor unselected
Definition spi.h:62
@ SPIMSBFirst
Definition spi.h:108
@ SPIDss8bit
Definition spi.h:86
SPI peripheral structure.
Definition spi.h:171
uint16_t foo
Definition main_demo5.c:58
static uint8_t readRegister_blocking(struct pmw3901_t *pmw, uint8_t addr)
Definition pmw3901.c:55
#define PMW3901_RAD_PER_PX
Definition pmw3901.c:38
#define PMW3901_REG_MOTION
Definition pmw3901.c:47
#define wait_ms(_ms)
Definition pmw3901.c:101
#define PMW3901_SPI_CDIV
Definition pmw3901.c:44
void pmw3901_init(struct pmw3901_t *pmw, struct spi_periph *periph, uint8_t slave_idx)
Definition pmw3901.c:232
static void writeRegister_blocking(struct pmw3901_t *pmw, uint8_t addr, uint8_t data)
Definition pmw3901.c:77
#define PMW3901_REG_DELTA_X_H
Definition pmw3901.c:49
#define readRegister(_addr)
Definition pmw3901.c:100
#define PMW3901_REG_DELTA_X_L
Definition pmw3901.c:48
#define PMW3901_REG_DELTA_Y_H
Definition pmw3901.c:51
#define writeRegister(_addr, _data)
Definition pmw3901.c:99
bool pmw3901_get_data(struct pmw3901_t *pmw, int16_t *delta_x, int16_t *delta_y)
Definition pmw3901.c:260
#define PMW3901_REG_DELTA_Y_L
Definition pmw3901.c:50
static void initializeSensor(struct pmw3901_t *pmw)
Definition pmw3901.c:104
static void pmw3901_thd(void *arg)
Definition pmw3901.c:211
volatile uint8_t spi_output_buf[SPI_BUFFER_SIZE]
Definition pmw3901.h:67
struct spi_periph * periph
Definition pmw3901.h:62
pprz_thread_t thd_handle
Definition pmw3901.h:63
volatile uint8_t spi_input_buf[SPI_BUFFER_SIZE]
Definition pmw3901.h:66
float rad_per_px
Definition pmw3901.h:74
int16_t delta_y
Definition pmw3901.h:72
struct spi_transaction trans
Definition pmw3901.h:65
bool data_available
Definition pmw3901.h:73
enum pmw3901_state state
Definition pmw3901.h:68
int16_t delta_x
Definition pmw3901.h:71
@ PMW3901_IDLE
Definition pmw3901.h:53
pprz_bsem_t bsem
Definition pmw3901.h:64
Architecture independent timing functions.
short int16_t
Typedef defining 16 bit short type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.