]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lib.git/blob - rpp/src/drv/din.c
Clarify DIN documentation and fix a bug
[pes-rpp/rpp-lib.git] / rpp / src / drv / din.c
1 /*
2  * din.c
3  *
4  *  Created on: 17.12.2012
5  *      Author: Michal Horn
6  *
7  *  This file contains functions to control DIN
8  *  Voltage on each pin can be set
9  *  switch to ground or to battery on programable pins can be set
10  *  interrupts on each pins can be disabled and enabled
11  */
12
13
14 #include "drv/drv.h"
15
16 /** Prepared command */
17 uint32_t din_spi_cmd = DIN_SPICMD_INIT_VAL;
18 /** Shadow variable used during sending */
19 uint32_t din_spi_cmd_sh = DIN_SPICMD_INIT_VAL;
20 /** Stored response from SPI */
21 uint32_t din_spi_resp = 0;
22 /** Prepared command for change status on SP pins */
23 uint32_t pin_st_p_cmd;
24 /** Prepared command for change status on SG pins */
25 uint32_t pin_st_g_cmd;
26 /** Prepared command for disabling interrupt on SP pins */
27 uint32_t pin_int_p_cmd;
28 /** Prepared command for disabling interrupt on SG pins */
29 uint32_t pin_int_g_cmd;
30
31 /** Signal for state cmd transfer */
32 uint8_t transfer_state_cmd = 0;
33 /** Signal for interrupt cmd trasfer */
34 uint8_t transfer_interrupt_cmd = 0;
35
36 /** Indexes of bits in status commands assigned to pins */
37 static const uint32_t din_set_pin_st_i[]  = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7};
38 /** Indexes of bits in switch-to commands assigned to pins */
39 static const uint32_t din_set_pin_pr_i[]  = {0, 1, 2, 3, 4, 5, 6, 7};
40
41 const static uint32_t dsc_pin_map[8U] = {
42     PIN_DSC_DIN8,
43     PIN_DSC_DIN9,
44     PIN_DSC_DIN10,
45     PIN_DSC_DIN11,
46     PIN_DSC_DIN12,
47     PIN_DSC_DIN13,
48     PIN_DSC_DIN14,
49     PIN_DSC_DIN15
50 };
51
52
53 // See mcp4922.pdf p. 24
54 // Options:
55 //   Bit 13: Output Gain Selection bit set = 1x (VOUT = VREF * D/4096)
56 //   Bit 15: DACA (0) or DACB (1) Selection bit.
57 #define DACA_INIT_VAL   (_BV(13) | _BV(12)          )
58 #define DACB_INIT_VAL   (_BV(13) | _BV(12) | _BV(15))
59
60 int8_t drv_din_ref(uint16_t ref_a, uint16_t ref_b)
61 {
62     uint16_t cmd;
63
64     // Get descriptor
65     uint32_t commands[2];
66     port_desc_t* desc = hal_port_get_dsc(PORT_NAME_DACDREF, -1);
67
68     // Send command for DAC A
69     cmd = DACA_INIT_VAL | (ref_a & 0x0FFF);
70
71     commands[0] = (cmd & 0xFF00) >> 8;
72     commands[1] = (cmd & 0xFF);
73     desc->port_setfnc_ptr(desc->config, desc->numValues, commands);
74
75     // Send command for DAC B
76     cmd = DACB_INIT_VAL | (ref_b & 0x0FFF);
77
78     commands[0] = (cmd & 0xFF00) >> 8;
79     commands[1] = (cmd & 0xFF);
80     desc->port_setfnc_ptr(desc->config, desc->numValues, commands);
81
82     // Fixme: check SPI return value.
83     return SUCCESS;
84 }
85
86
87 int8_t drv_din_get_varthr(uint8_t pin) {
88
89     // Check range
90     if((pin < 8) || (pin > 15)) {
91         return FAILURE;
92     }
93
94     return hal_gpio_pin_get_value(dsc_pin_map[pin - 8]);
95 }
96
97 /**
98  * Set programmable pin DIN_SP according bits in argument as switch-to-battery (1) or switch-to-ground(0)
99  * @param word  8-bit array representing switch-to state
100  */
101 void din_set_pr(uint8_t word) {
102     int i;
103     uint8_t val;
104     din_spi_cmd = 1 << 16;  // Settings command
105
106     for (i = 0; i < 8; i++, word >>= 1) {
107         val = word&0x1;
108         if (val == 1) {
109             din_spi_cmd |= 1 << din_set_pin_pr_i[i];
110         }
111         else if (val == 0) {
112             din_spi_cmd &= ~(1 << din_set_pin_pr_i[i]);
113         }
114     }
115 }
116
117 /**
118  * Set DIN pins to be tri-state (1) or Active (0)
119  * @param sp_state 16-bit variable representing state of SP pins. (0 - active, 1 - tri-state).
120  * @param sg_state 16-bit variable representing state of SG pins. (0 - active, 1 - tri-state).
121  */
122 void din_set_stat(uint16_t sp_state, uint16_t sg_state) {
123     int i;
124     uint16_t val;
125     uint32_t state = (sp_state&0xFF)|((sg_state&0xFF)<<8);
126     uint32_t* pin_cmd_ptr = NULL;
127     pin_st_p_cmd = 0x9 << 16;       // Set command for SP pins
128     pin_st_g_cmd = 0xA << 16;       // Set command for SG pins
129     for (i = 0; i < 16; i++,state >>= 1) {
130         val = state&0x1;
131         if (i < 8) {    // First 8 pins SP0 - SP7
132             pin_cmd_ptr = &pin_st_p_cmd;
133         }
134         else { // Another 8 pins SG0 - SG7
135             pin_cmd_ptr = &pin_st_g_cmd;
136         }
137
138         if (val) {
139             *pin_cmd_ptr |= 1 << din_set_pin_st_i[i];
140         }
141         else {
142             *pin_cmd_ptr &= ~(1 << din_set_pin_st_i[i]);
143         }
144     }
145     transfer_state_cmd = 1; // Enable transfer of two commands at once
146 }
147
148 /**
149  * Enable/disable interrupts for DIN pins as well as acting pins as wake-up
150  * @param sp_int_enable 16-bit variable representing interrupt enablers for SP pins (0 - disable wake-up and interrupt, 1 - enable interrupt).
151  * @param sg_int_enable 16-bit variable representing interrupt enablers for SG pins (0 - disable wake-up and interrupt, 1 - enable interrupt).
152  */
153 void din_set_int(uint16_t sp_int_enable, uint16_t sg_int_enable) {
154     int i;
155     uint16_t val;
156     uint32_t int_enable = (sp_int_enable&0xFF)|((sg_int_enable&0xFF)<<8); // LSB
157     uint32_t* pin_cmd_ptr = NULL;
158     pin_int_p_cmd = 0x2 << 16;      // Set command for SP pins
159     pin_int_g_cmd = 0x3 << 16;      // Set command for SG pins
160     for (i = 0; i < 16; i++,int_enable >>= 1) {
161         val = int_enable&0x1;
162         if (i < 8) {    // First 8 pins SP0 - SP7
163             pin_cmd_ptr = &pin_int_p_cmd;
164         }
165         else { // Another 8 pins SG0 - SG7
166             pin_cmd_ptr = &pin_int_g_cmd;
167         }
168
169         if (val) {
170             *pin_cmd_ptr |= 1 << din_set_pin_st_i[i];
171         }
172         else {
173             *pin_cmd_ptr &= ~(1 << din_set_pin_st_i[i]);
174         }
175     }
176     transfer_interrupt_cmd = 1; // Enable transfer of two commands at once
177 }
178
179 /**
180  * Prepare reset command to be sent through spi
181  */
182 void din_reset() {
183     din_spi_cmd = 0x7F0000;
184 }
185
186 /**
187  * Prepare switch status command to be sent through spi
188  */
189 void din_switch_st() {
190     din_spi_cmd = 0x0;
191 }
192
193 /**
194  * Get values of all DIN pins in form of 16-bit word DIN15,...,DIN0
195  * @return values of all pins.
196  */
197 uint16_t din_get_val_word()
198 {
199     // How it should be.
200     //uint16_t sp = ((din_spi_resp >> 14) & 0x00FF);
201     //uint16_t sg = ((din_spi_resp << 8 ) & 0xFF00);
202
203     // How it actually is.
204     // Ignore datasheet, this is the actual response from the SPI driver:
205     // [xxxx xxxx][SG7-SG0][SP1 SP0 yy yyyy][zz SP7-SP2]
206     //  x: Unknown.
207     //  y: Maybe SG13-SG8, but untested.
208     //  z: Maybe therm flag and int flag.
209     // For SP: First get SP7-SP2 right, then add SP1 and SP0
210     uint16_t sp = ((din_spi_resp << 2) & 0x00FF) | ((din_spi_resp >> 14) & 0x3);
211     uint16_t sg = ((din_spi_resp >> 8) & 0xFF00);
212     uint16_t word = sg | sp;
213     return word;
214 }
215
216 /**
217  * Switch copy command, prepared by other functions, to shadow variable,
218  * convert command to MSB,
219  * transfer command to DIN
220  * store spi response
221  * return spi response
222  */
223 int din_spi_transfer_mst() {
224     port_desc_t* desc;
225     din_spi_cmd_sh = din_spi_cmd;
226     desc = hal_port_get_dsc(PORT_NAME_DINSPI, -1);
227     uint32_t commands[3];
228     commands[0] = (din_spi_cmd_sh & 0xFF0000) >> 16;
229     commands[1] = (din_spi_cmd_sh & 0xFF00) >> 8;
230     commands[2] = (din_spi_cmd_sh & 0xFF);
231
232     din_spi_resp = desc->port_setfnc_ptr(desc->config, desc->numValues, commands);
233     return din_spi_resp;
234 }
235
236 /**
237  * Transfer prepared commands through spi
238  * With highest priority send state modification commands
239  * With secondary priority send interrupt commands
240  * In the end send other commands
241  *
242  * Store response from spi
243  * Returns spi response
244  */
245 int din_spi_transfer() {
246     if (transfer_state_cmd) {
247         din_spi_cmd = pin_st_p_cmd;
248         din_spi_transfer_mst();
249         din_spi_cmd = pin_st_g_cmd;
250         transfer_state_cmd = 0;
251     }
252     else if (transfer_interrupt_cmd) {
253         din_spi_cmd = pin_int_p_cmd;
254         din_spi_transfer_mst();
255         din_spi_cmd = pin_int_g_cmd;
256         transfer_interrupt_cmd = 0;
257     }
258     return din_spi_transfer_mst();
259 }
260
261 /**
262  * Get latest response from SPI. Function does not send anything.
263  * @return latest spi response
264  */
265 int din_spi_response() {
266     return din_spi_resp;
267 }
268
269 /**
270  * Get last command sent on SPI
271  * @return latest sent command
272  */
273 int din_spi_get_cmd() {
274     return din_spi_cmd;
275 }