]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_A2F200_IAR_and_Keil/MicroSemi_Code/drivers/mss_ace/ace_transform.c
Create directory structure to hold the (not yet created) Keil and IAR demo projects...
[freertos] / Demo / CORTEX_A2F200_IAR_and_Keil / MicroSemi_Code / drivers / mss_ace / ace_transform.c
1 /*******************************************************************************\r
2  * (c) Copyright 2010 Actel Corporation.  All rights reserved.\r
3  *\r
4  *  This file contains the implementation of the functions used to dynamically\r
5  *  control the linear transforms applied by the ACE post processing engine to\r
6  *  the samples read from the SSE.\r
7  *\r
8  * SVN $Revision: 2908 $\r
9  * SVN $Date: 2010-08-20 16:01:28 +0100 (Fri, 20 Aug 2010) $\r
10  */\r
11 \r
12 #include "mss_ace.h"\r
13 #include "mss_ace_configurator.h"\r
14 #include "mtd_data.h"\r
15 #include "envm_layout.h"\r
16 #include "../../CMSIS/a2fxxxm3.h"\r
17 #include "../../CMSIS/mss_assert.h"\r
18 #include "../../drivers_config/mss_ace/ace_config.h"\r
19 \r
20 #ifdef __cplusplus\r
21 extern "C" {\r
22 #endif \r
23 \r
24 /*\r
25  * The ACE_set_linear_transform() is only available when using ACE configuration\r
26  * files generated by Libero 9.1 or later.\r
27  */\r
28 #ifdef ACE_CFG_DATA_FORMAT_VERSION\r
29 \r
30 /*------------------------------------------------------------------------------\r
31  * Masks ans shift values used to derive the ABPS ranges from the analog block\r
32  * configuration.\r
33  */\r
34 #define ABPS1_CFG_BITS_MASK     (uint32_t)0x06\r
35 #define ABPS1_CFG_BITS_SHIFT    (uint32_t)1\r
36 \r
37 #define ABPS2_CFG_BITS_MASK     (uint32_t)0x60\r
38 #define ABPS2_CFG_BITS_SHIFT    (uint32_t)5\r
39 \r
40 /*------------------------------------------------------------------------------\r
41  * One Bit DAC definitions.\r
42  */\r
43 #define OBD_CURRENT     (uint32_t)1\r
44 #define OBD_VOLTAGE     (uint32_t)0\r
45 \r
46 #define OBD_MODE_MASK    (uint32_t)0x01\r
47 #define OBD_CHOPPING_MASK    (uint32_t)0x02\r
48 \r
49 /*-------------------------------------------------------------------------*//**\r
50    Neutral factor and offset for m*x + c trnasform.\r
51  */\r
52 #define NEUTRAL_M_FACTOR    0x4000\r
53 #define NEUTRAL_C_OFFSET    0x0000\r
54 \r
55 /*-------------------------------------------------------------------------*//**\r
56   Enumearation of the various input channel types. This is used to differentiate\r
57   between channel types in order to extract the relevant factory calibration\r
58   data(m1 and c1).\r
59  */\r
60 typedef enum channel_type\r
61 {\r
62     ABPS1_CHAN = 0,\r
63     ABPS2_CHAN,\r
64     CMB_CHAN,\r
65     TMB_CHAN,\r
66     DIRECT_ADC_INPUT_CHAN,\r
67     OBDOUT_CHAN,\r
68     FLOATING_CHAN\r
69 } cal_channel_type_t;\r
70 \r
71 /*-------------------------------------------------------------------------*//**\r
72   This data structure is used to store factory calibration data for a specific\r
73   analog input.\r
74  */\r
75 typedef struct __channel_calibration_t\r
76 {\r
77     uint16_t mext;\r
78     uint16_t m1;\r
79     uint16_t c1;\r
80 } channel_calibration_t;\r
81 \r
82 /*-------------------------------------------------------------------------*//**\r
83   Local functions\r
84  */\r
85 int32_t extend_sign\r
86 (\r
87     uint16_t x\r
88 );\r
89 \r
90 uint32_t adjust_to_24bit_ace_format\r
91 (\r
92     int64_t signed48\r
93 );\r
94 \r
95 uint32_t adjust_to_16bit_ace_format\r
96 (\r
97     int64_t signed48\r
98 );\r
99 \r
100 void get_calibration\r
101 (\r
102     adc_channel_id_t channel_id,\r
103     channel_calibration_t * p_calibration\r
104 );\r
105 \r
106 void write_transform_coefficients\r
107 (\r
108     ace_channel_handle_t channel_handle,\r
109         uint32_t m,\r
110         uint32_t c\r
111 );\r
112 \r
113 /*-------------------------------------------------------------------------*//**\r
114           \r
115  */\r
116 extern const uint8_t g_ace_external_varef_used[ACE_NB_OF_ADC];\r
117 \r
118 extern ace_channel_desc_t g_ace_channel_desc_table[ACE_NB_OF_INPUT_CHANNELS];\r
119 \r
120 extern const ppe_transforms_desc_t g_ace_ppe_transforms_desc_table[ACE_NB_OF_INPUT_CHANNELS];\r
121 \r
122 /*------------------------------------------------------------------------------\r
123  * Pointer to the manufacturing test data containing trimming information\r
124  * generated during manufacturing.\r
125  */\r
126 static const mtd_data_t * const p_mtd_data = (mtd_data_t *)MTD_ADDRESS;\r
127 \r
128 /*-------------------------------------------------------------------------*//**\r
129   See "mss_ace.h" for details of how to use this function.\r
130  */\r
131 int16_t ACE_get_default_m_factor\r
132 (\r
133     ace_channel_handle_t channel_handle\r
134 )\r
135 {\r
136     ASSERT( channel_handle < NB_OF_ACE_CHANNEL_HANDLES );\r
137     \r
138     return g_ace_ppe_transforms_desc_table[channel_handle].m_ppe_offset;\r
139 }\r
140 \r
141 /*-------------------------------------------------------------------------*//**\r
142   See "mss_ace.h" for details of how to use this function.\r
143  */\r
144 int16_t ACE_get_default_c_offset\r
145 (\r
146     ace_channel_handle_t channel_handle\r
147 )\r
148 {\r
149     ASSERT( channel_handle < NB_OF_ACE_CHANNEL_HANDLES );\r
150     \r
151     return g_ace_ppe_transforms_desc_table[channel_handle].c_ppe_offset;\r
152 }\r
153 \r
154 /*-------------------------------------------------------------------------*//**\r
155   See "mss_ace.h" for details of how to use this function.\r
156   \r
157         m = m2 * m1 * mext\r
158         c = (m2 * c1 * mext) + (c2 * mext)\r
159  */\r
160 void ACE_set_linear_transform\r
161 (\r
162     ace_channel_handle_t channel_handle,\r
163         int16_t m2,\r
164         int16_t c2\r
165 )\r
166 {\r
167     adc_channel_id_t channel_id;\r
168         uint32_t m;\r
169         uint32_t c;\r
170         int32_t m32;\r
171         int64_t m64;\r
172         int32_t c32;\r
173         int64_t c64_1;\r
174     int64_t c64_2;\r
175     uint16_t m1;\r
176     uint16_t c1;\r
177     uint16_t mext;\r
178     \r
179     channel_calibration_t calibration;\r
180     \r
181     ASSERT( channel_handle < NB_OF_ACE_CHANNEL_HANDLES );\r
182     \r
183     if(channel_handle < NB_OF_ACE_CHANNEL_HANDLES)\r
184     {\r
185         channel_id = g_ace_channel_desc_table[channel_handle].signal_id;\r
186         \r
187         get_calibration(channel_id, &calibration);\r
188         \r
189         m1 = calibration.m1;\r
190         c1 = calibration.c1;\r
191         \r
192         mext = calibration.mext;\r
193 \r
194         /* \r
195          * m = m2 * m1 * mext\r
196          */\r
197         m32 = extend_sign(m2) * extend_sign(m1);\r
198         m64 = (int64_t)m32 * extend_sign(mext);\r
199         \r
200         /* Convert 48-bit result to 32-bit ACE format result. */\r
201         m = adjust_to_16bit_ace_format(m64);\r
202 \r
203         /*\r
204          * c = (m2 * c1 * mext) + (c2 * mext)\r
205          */\r
206         c32 = extend_sign(m2) * extend_sign(c1);\r
207         c64_1 = (int64_t)c32 * extend_sign(mext);\r
208 \r
209         c64_2 = ((int64_t)(extend_sign(c2) * extend_sign(mext))) << 14;\r
210         \r
211         c = adjust_to_24bit_ace_format(c64_1 + c64_2);\r
212         \r
213         write_transform_coefficients(channel_handle, m, c);\r
214     }\r
215 }\r
216 \r
217 /*-------------------------------------------------------------------------*//**\r
218     Extend 16-bit signed number to 32-bit signed number.\r
219  */\r
220 int32_t extend_sign\r
221 (\r
222     uint16_t x\r
223 )\r
224 {\r
225     int32_t y;\r
226     const uint32_t sign_bit_mask = 0x00008000u;\r
227     \r
228     y = (x ^ sign_bit_mask) - sign_bit_mask;\r
229     \r
230     return y;\r
231 }\r
232 \r
233 /*-------------------------------------------------------------------------*//**\r
234   Take a 48-bit signed number, adjust it for saturation in the range -8 to\r
235   +7.999, translate into 24-bit ACE format.\r
236  */\r
237 uint32_t adjust_to_24bit_ace_format\r
238 (\r
239     int64_t signed48\r
240 )\r
241 {\r
242     int32_t ace24_format;\r
243     const int64_t MAX_POSITIVE = 0x00001FFFFFFFFFFFuLL; /* +7.9999 */\r
244     const int64_t MIN_NEGATIVE = 0xFFFF200000000000uLL; /* -8 */\r
245     \r
246     /* Check saturation. */\r
247     if(signed48 > MAX_POSITIVE)\r
248     {\r
249         signed48 = MAX_POSITIVE;\r
250     }\r
251     else if(signed48 < MIN_NEGATIVE)\r
252     {\r
253         signed48 = MIN_NEGATIVE;\r
254     }\r
255     \r
256     /* Adjust to 24-bit ACE format. */\r
257     ace24_format = (uint32_t)(signed48 >> 14);\r
258     \r
259     return ace24_format;\r
260 }\r
261 \r
262 /*-------------------------------------------------------------------------*//**\r
263   Take a 48-bit signed number, adjust it for saturation in the range -8 to\r
264   +7.999, translate into 16-bit ACE format.\r
265  */\r
266 uint32_t adjust_to_16bit_ace_format\r
267 (\r
268     int64_t signed48\r
269 )\r
270 {\r
271     int32_t ace24_format;\r
272     const int64_t MAX_POSITIVE = 0x00001FFFFFFFFFFFuLL; /* +7.9999 */\r
273     const int64_t MIN_NEGATIVE = 0xFFFF200000000000uLL; /* -8 */\r
274     \r
275     /* Check saturation. */\r
276     if(signed48 > MAX_POSITIVE)\r
277     {\r
278         signed48 = MAX_POSITIVE;\r
279     }\r
280     else if(signed48 < MIN_NEGATIVE)\r
281     {\r
282         signed48 = MIN_NEGATIVE;\r
283     }\r
284     \r
285     /* Adjust to 24-bit ACE format. */\r
286     ace24_format = (uint32_t)(signed48 >> 20);\r
287     \r
288     return ace24_format;\r
289 }\r
290 \r
291 /*-------------------------------------------------------------------------*//**\r
292           \r
293  */\r
294 void get_calibration\r
295 (\r
296     adc_channel_id_t channel_id,\r
297     channel_calibration_t * p_calibration\r
298 )\r
299 {\r
300     const uint32_t channel_mask = 0x0000000F;\r
301     const uint32_t CMB_MUX_SEL_MASK = 0x01;\r
302     const uint32_t TMB_MUX_SEL_MASK = 0x01;\r
303     \r
304     const cal_channel_type_t channel_type_lut[16] =\r
305     {\r
306         FLOATING_CHAN,\r
307         ABPS1_CHAN,\r
308         ABPS2_CHAN,\r
309         CMB_CHAN,\r
310         TMB_CHAN,\r
311         ABPS1_CHAN,\r
312         ABPS2_CHAN,\r
313         CMB_CHAN,\r
314         TMB_CHAN,\r
315         DIRECT_ADC_INPUT_CHAN,\r
316         DIRECT_ADC_INPUT_CHAN,\r
317         DIRECT_ADC_INPUT_CHAN,\r
318         DIRECT_ADC_INPUT_CHAN,\r
319         FLOATING_CHAN,\r
320         FLOATING_CHAN,\r
321         OBDOUT_CHAN\r
322     };\r
323     \r
324     cal_channel_type_t channel_type;\r
325     uint32_t channel_nb;\r
326     uint32_t adc_nb;\r
327     uint32_t range;\r
328     uint32_t quad_id;\r
329     mtd_calibration_mc_t const * p_mc_coeff = 0;\r
330     \r
331     channel_nb = channel_id & channel_mask;\r
332     channel_type = channel_type_lut[channel_nb];\r
333     adc_nb = ((uint32_t)channel_id & 0x30u) >> 4u;\r
334     \r
335     quad_id = adc_nb * 2;\r
336     \r
337     if ( (channel_nb > 4) && (channel_nb < 9) ) { ++quad_id; }\r
338     \r
339     switch ( channel_type )\r
340     {\r
341     case ABPS1_CHAN:\r
342         range = (ACE->ACB_DATA[quad_id].b8 & ABPS1_CFG_BITS_MASK) >> ABPS1_CFG_BITS_SHIFT;\r
343         p_mc_coeff = &p_mtd_data->abps_calibration[quad_id][0][range];\r
344         break;\r
345         \r
346     case ABPS2_CHAN:\r
347         range = (ACE->ACB_DATA[quad_id].b8 & ABPS2_CFG_BITS_MASK) >> ABPS2_CFG_BITS_SHIFT;\r
348         p_mc_coeff = &p_mtd_data->abps_calibration[quad_id][1][range];\r
349         break;\r
350         \r
351     case CMB_CHAN:\r
352         {\r
353             uint32_t cmb_mux_sel = (uint32_t)ACE->ACB_DATA[quad_id].b9 & CMB_MUX_SEL_MASK;\r
354             if ( cmb_mux_sel == 0 )\r
355             {   /* current monitor */\r
356                 p_mc_coeff = &p_mtd_data->cm_calibration[quad_id];\r
357             }\r
358             else\r
359             {   /* direct input */\r
360                 p_mc_coeff = &p_mtd_data->quads_direct_input_cal[quad_id][0];\r
361             }\r
362         }\r
363         break;\r
364         \r
365     case TMB_CHAN:\r
366         {\r
367             uint32_t tmb_mux_sel = (uint32_t)ACE->ACB_DATA[quad_id].b10 & TMB_MUX_SEL_MASK;\r
368             if ( tmb_mux_sel == 0 )\r
369             {   /* temperature monitor */\r
370                 p_mc_coeff = &p_mtd_data->tm_calibration[quad_id];\r
371             }\r
372             else\r
373             {   /* direct input */\r
374                 p_mc_coeff = &p_mtd_data->quads_direct_input_cal[quad_id][1];\r
375             }\r
376         }\r
377         break;\r
378         \r
379     case DIRECT_ADC_INPUT_CHAN:\r
380         {\r
381             const uint32_t channel_to_direct_in_lut[16]\r
382                 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0};\r
383             uint32_t direct_in_id;\r
384             \r
385             direct_in_id = channel_to_direct_in_lut[channel_id & channel_mask];\r
386             p_mc_coeff = &p_mtd_data->adc_direct_input_cal[adc_nb][direct_in_id];\r
387         }\r
388         break;\r
389         \r
390     case OBDOUT_CHAN:\r
391         {\r
392             uint32_t obd_mode = (uint32_t)ACE->ACB_DATA[quad_id].b6 & OBD_MODE_MASK;\r
393             uint32_t chopping_option = (uint32_t)ACE->ACB_DATA[quad_id].b6 & OBD_CHOPPING_MASK;\r
394             if (obd_mode > 0)\r
395             {\r
396                 obd_mode = 1;\r
397             }\r
398             if (chopping_option > 0)\r
399             {\r
400                 chopping_option = 1;\r
401             }\r
402             p_mc_coeff = &p_mtd_data->obd_calibration[adc_nb][obd_mode][chopping_option];\r
403         }\r
404         break;\r
405        \r
406     case FLOATING_CHAN:\r
407     default:\r
408         /* Give neutral values is invalid channel. */\r
409         p_calibration->m1 = NEUTRAL_M_FACTOR;\r
410         p_calibration->c1 = NEUTRAL_C_OFFSET;\r
411         break;\r
412     }\r
413     \r
414     if (p_mc_coeff != 0)\r
415     {\r
416         p_calibration->m1 = p_mc_coeff->m;\r
417         p_calibration->c1 = p_mc_coeff->c;\r
418         \r
419     }\r
420     \r
421     /*--------------------------------------------------------------------------\r
422       Retrieve the value of the mext factor. This depends if external VAREF is\r
423       used by the ADC sampling the analog input channel.\r
424      */\r
425     if (g_ace_external_varef_used[adc_nb])\r
426     {\r
427         p_calibration->mext = p_mtd_data->global_settings.varef_m;\r
428     }\r
429     else\r
430     {\r
431         p_calibration->mext = NEUTRAL_M_FACTOR;\r
432     }\r
433 }\r
434 \r
435 /*-------------------------------------------------------------------------*//**\r
436   Write new m and c transform factors into the PPE RAM. The m and c factors\r
437   should be in 32-bit ACE number format. The factors will be merged with\r
438   relevant PE opcode into PPE RAM. The 32-bit factors are shifted right by one\r
439   byte giving a 24-bit ACE number which is then merged with an 8-bit PPE opcode\r
440   located in the most significant byte of the PPE RAM location.\r
441  */\r
442 void write_transform_coefficients\r
443 (\r
444     ace_channel_handle_t channel_handle,\r
445         uint32_t m,\r
446         uint32_t c\r
447 )\r
448 {\r
449     uint16_t m_ppe_offset;\r
450     uint16_t c_ppe_offset;\r
451     const uint32_t PPE_OPCODE_MASK = 0xFF000000u;\r
452     \r
453     m_ppe_offset = g_ace_ppe_transforms_desc_table[channel_handle].m_ppe_offset;\r
454     c_ppe_offset = g_ace_ppe_transforms_desc_table[channel_handle].c_ppe_offset;\r
455     \r
456     ACE->PPE_RAM_DATA[m_ppe_offset]\r
457         = (ACE->PPE_RAM_DATA[m_ppe_offset] & PPE_OPCODE_MASK) | (m >> 8u);\r
458         \r
459     ACE->PPE_RAM_DATA[c_ppe_offset]\r
460         = (ACE->PPE_RAM_DATA[c_ppe_offset] & PPE_OPCODE_MASK) | (c >> 8u);\r
461 }\r
462 \r
463 #endif  /* ACE_CFG_DATA_FORMAT_VERSION */\r
464 \r
465 #ifdef __cplusplus\r
466 }\r
467 #endif\r