-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmcp3914.c
162 lines (145 loc) · 4.51 KB
/
mcp3914.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include <assert.h>
#include <stm32_platform.h>
#include "mcp3914.h"
#include <spi.h>
#include <clk_enable.h>
extern void delay_us(const uint32_t usec);
void mcp3914_port_configure(const struct MCP3914_PORT_CFG *port, enum GPIO_OUT_SPEED pin_speed, uint32_t spi_prescaler)
{
gpio_pin_write(port->reset_pin, 1);
gpio_pin_write(port->cs_pin, 1);
clk_enable(AFIO);
clk_enable(port->reset_pin.port);
clk_enable(port->sck_pin.port);
clk_enable(port->mosi_pin.port);
clk_enable(port->miso_pin.port);
clk_enable(port->cs_pin.port);
clk_enable(port->dr_pin.port);
gpio_configure_out(port->reset_pin.port, port->reset_pin.pin, GPIO_OUT_PP, pin_speed);
gpio_configure_af(port->sck_pin.port, port->sck_pin.pin, GPIO_OUT_PP, pin_speed);
gpio_configure_af(port->mosi_pin.port, port->mosi_pin.pin, GPIO_OUT_PP, pin_speed);
gpio_configure_in(port->miso_pin.port, port->miso_pin.pin);
gpio_configure_out(port->cs_pin.port, port->cs_pin.pin, GPIO_OUT_PP, pin_speed);
gpio_configure_in(port->dr_pin.port, port->dr_pin.pin);
gpio_configure_in_pull(port->dr_pin.port, port->dr_pin.pin, GPIO_PULLUP); // single device configuration, requires DR_HIZ setting TODO NOPULL ????
// reset MCP3914, may not be necessary
gpio_pin_write(port->reset_pin, 0);
delay_us(1000);
gpio_pin_write(port->reset_pin, 1);
delay_us(1000);
// TODO: 16 bit SPI
clk_enable(port->spi);
port->spi->CR1 = SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI | spi_prescaler;
port->spi->CR1 |= SPI_CR1_SPE;
clk_enable(DMA_CHANNEL_TO_DMA(port->spi_rx_dma.dma_channel));
clk_enable(DMA_CHANNEL_TO_DMA(port->spi_tx_dma.dma_channel));
}
static uint8_t READ_CMD(uint8_t address, uint8_t reg)
{
return (address << 6) | (reg << 1) | MCP3914_CMD_READ_MASK;
}
static uint8_t WRITE_CMD(uint8_t address, uint8_t reg)
{
return (address << 6) | (reg << 1) | MCP3914_CMD_WRITE_MASK;
}
void mcp_3914_parse_statuscom(uint32_t statuscom, unsigned *channel_width, unsigned *repeat)
{
switch (statuscom & MCP3914_STATUSCOM_WIDTH_DATA_MASK)
{
case MCP3914_STATUSCOM_WIDTH_DATA_16:
*channel_width = 2;
break;
case MCP3914_STATUSCOM_WIDTH_DATA_24:
*channel_width = 3;
break;
case MCP3914_STATUSCOM_WIDTH_DATA_32S:
case MCP3914_STATUSCOM_WIDTH_DATA_32Z:
*channel_width = 4;
break;
}
switch (statuscom & MCP3914_STATUSCOM_READ_MASK)
{
case MCP3914_STATUSCOM_READ_ONE:
*repeat = 1;
break;
case MCP3914_STATUSCOM_READ_GROUP:
*repeat = 2; // TODO: incorrect for all registers
break;
case MCP3914_STATUSCOM_READ_TYPES:
*repeat = 8; // TODO: incorrect for all registers
break;
case MCP3914_STATUSCOM_READ_ALL:
*repeat = 32;
break;
}
}
void mcp3914_write_reg(const struct MCP3914_PORT_CFG *cfg, enum MCP3914_REG reg, uint32_t val)
{
mcp3914_select(cfg);
spi_read_write(cfg->spi, WRITE_CMD(MCP3914_CMD_ADDRESS, reg));
if (reg == MCP3914_REG_MOD)
spi_read_write(cfg->spi, (val >> 24) & 0xff);
spi_read_write(cfg->spi, (val >> 16) & 0xff);
spi_read_write(cfg->spi, (val >> 8) & 0xff);
spi_read_write(cfg->spi, val & 0xff);
mcp3914_deselect(cfg);
}
static uint8_t mcp3914_reg_width(enum MCP3914_REG reg)
{
if (reg >= MCP3914_REG_CHANNEL_BASE
&& reg < MCP3914_REG_CHANNEL_BASE + MCP3914_NUM_CHANNELS)
return 2; // minimal size
else
if (reg == MCP3914_REG_MOD)
return 4;
else
return 3;
}
uint32_t mcp3914_read_reg(const struct MCP3914_PORT_CFG *cfg, enum MCP3914_REG reg)
{
uint32_t val = 0;
unsigned len = mcp3914_reg_width(reg);
assert(len >= 2 && len <= 4);
mcp3914_select(cfg);
spi_read_write(cfg->spi, READ_CMD(MCP3914_CMD_ADDRESS, reg));
switch (len)
{
case 4:
val |= spi_read_write(cfg->spi, 0xff) << 24;
case 3:
val |= spi_read_write(cfg->spi, 0xff) << 16;
case 2:
val |= spi_read_write(cfg->spi, 0xff) << 8;
val |= spi_read_write(cfg->spi, 0xff);
}
mcp3914_deselect(cfg);
return val;
}
uint32_t mcp3914_read_channel(const struct MCP3914_PORT_CFG *cfg, unsigned channel, unsigned len)
{
uint32_t val = 0;
assert(len >= 2 && len <= 4);
mcp3914_select(cfg);
spi_read_write(cfg->spi, READ_CMD(MCP3914_CMD_ADDRESS, MCP3914_REG_CHANNEL_BASE + channel));
switch (len)
{
case 4:
val |= spi_read_write(cfg->spi, 0xff) << 24;
case 3:
val |= spi_read_write(cfg->spi, 0xff) << 16;
case 2:
val |= spi_read_write(cfg->spi, 0xff) << 8;
val |= spi_read_write(cfg->spi, 0xff);
}
mcp3914_deselect(cfg);
return val;
}
void mcp3914_stream_start(const struct MCP3914_PORT_CFG *cfg, unsigned reg)
{
mcp3914_select(cfg);
spi_read_write(cfg->spi, READ_CMD(MCP3914_CMD_ADDRESS, reg));
}
void mcp3914_stream_end(const struct MCP3914_PORT_CFG *cfg)
{
mcp3914_deselect(cfg);
}