1 /*******************************************************************************
\r
2 * (c) Copyright 2010 Actel Corporation. All rights reserved.
\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
8 * SVN $Revision: 2908 $
\r
9 * SVN $Date: 2010-08-20 16:01:28 +0100 (Fri, 20 Aug 2010) $
\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
25 * The ACE_set_linear_transform() is only available when using ACE configuration
\r
26 * files generated by Libero 9.1 or later.
\r
28 #ifdef ACE_CFG_DATA_FORMAT_VERSION
\r
30 /*------------------------------------------------------------------------------
\r
31 * Masks ans shift values used to derive the ABPS ranges from the analog block
\r
34 #define ABPS1_CFG_BITS_MASK (uint32_t)0x06
\r
35 #define ABPS1_CFG_BITS_SHIFT (uint32_t)1
\r
37 #define ABPS2_CFG_BITS_MASK (uint32_t)0x60
\r
38 #define ABPS2_CFG_BITS_SHIFT (uint32_t)5
\r
40 /*------------------------------------------------------------------------------
\r
41 * One Bit DAC definitions.
\r
43 #define OBD_CURRENT (uint32_t)1
\r
44 #define OBD_VOLTAGE (uint32_t)0
\r
46 #define OBD_MODE_MASK (uint32_t)0x01
\r
47 #define OBD_CHOPPING_MASK (uint32_t)0x02
\r
49 /*-------------------------------------------------------------------------*//**
\r
50 Neutral factor and offset for m*x + c trnasform.
\r
52 #define NEUTRAL_M_FACTOR 0x4000
\r
53 #define NEUTRAL_C_OFFSET 0x0000
\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
60 typedef enum channel_type
\r
66 DIRECT_ADC_INPUT_CHAN,
\r
69 } cal_channel_type_t;
\r
71 /*-------------------------------------------------------------------------*//**
\r
72 This data structure is used to store factory calibration data for a specific
\r
75 typedef struct __channel_calibration_t
\r
80 } channel_calibration_t;
\r
82 /*-------------------------------------------------------------------------*//**
\r
90 uint32_t adjust_to_24bit_ace_format
\r
95 uint32_t adjust_to_16bit_ace_format
\r
100 void get_calibration
\r
102 adc_channel_id_t channel_id,
\r
103 channel_calibration_t * p_calibration
\r
106 void write_transform_coefficients
\r
108 ace_channel_handle_t channel_handle,
\r
113 /*-------------------------------------------------------------------------*//**
\r
116 extern const uint8_t g_ace_external_varef_used[ACE_NB_OF_ADC];
\r
118 extern ace_channel_desc_t g_ace_channel_desc_table[ACE_NB_OF_INPUT_CHANNELS];
\r
120 extern const ppe_transforms_desc_t g_ace_ppe_transforms_desc_table[ACE_NB_OF_INPUT_CHANNELS];
\r
122 /*------------------------------------------------------------------------------
\r
123 * Pointer to the manufacturing test data containing trimming information
\r
124 * generated during manufacturing.
\r
126 static const mtd_data_t * const p_mtd_data = (mtd_data_t *)MTD_ADDRESS;
\r
128 /*-------------------------------------------------------------------------*//**
\r
129 See "mss_ace.h" for details of how to use this function.
\r
131 int16_t ACE_get_default_m_factor
\r
133 ace_channel_handle_t channel_handle
\r
136 ASSERT( channel_handle < NB_OF_ACE_CHANNEL_HANDLES );
\r
138 return g_ace_ppe_transforms_desc_table[channel_handle].m_ppe_offset;
\r
141 /*-------------------------------------------------------------------------*//**
\r
142 See "mss_ace.h" for details of how to use this function.
\r
144 int16_t ACE_get_default_c_offset
\r
146 ace_channel_handle_t channel_handle
\r
149 ASSERT( channel_handle < NB_OF_ACE_CHANNEL_HANDLES );
\r
151 return g_ace_ppe_transforms_desc_table[channel_handle].c_ppe_offset;
\r
154 /*-------------------------------------------------------------------------*//**
\r
155 See "mss_ace.h" for details of how to use this function.
\r
158 c = (m2 * c1 * mext) + (c2 * mext)
\r
160 void ACE_set_linear_transform
\r
162 ace_channel_handle_t channel_handle,
\r
167 adc_channel_id_t channel_id;
\r
179 channel_calibration_t calibration;
\r
181 ASSERT( channel_handle < NB_OF_ACE_CHANNEL_HANDLES );
\r
183 if(channel_handle < NB_OF_ACE_CHANNEL_HANDLES)
\r
185 channel_id = g_ace_channel_desc_table[channel_handle].signal_id;
\r
187 get_calibration(channel_id, &calibration);
\r
189 m1 = calibration.m1;
\r
190 c1 = calibration.c1;
\r
192 mext = calibration.mext;
\r
195 * m = m2 * m1 * mext
\r
197 m32 = extend_sign(m2) * extend_sign(m1);
\r
198 m64 = (int64_t)m32 * extend_sign(mext);
\r
200 /* Convert 48-bit result to 32-bit ACE format result. */
\r
201 m = adjust_to_16bit_ace_format(m64);
\r
204 * c = (m2 * c1 * mext) + (c2 * mext)
\r
206 c32 = extend_sign(m2) * extend_sign(c1);
\r
207 c64_1 = (int64_t)c32 * extend_sign(mext);
\r
209 c64_2 = ((int64_t)(extend_sign(c2) * extend_sign(mext))) << 14;
\r
211 c = adjust_to_24bit_ace_format(c64_1 + c64_2);
\r
213 write_transform_coefficients(channel_handle, m, c);
\r
217 /*-------------------------------------------------------------------------*//**
\r
218 Extend 16-bit signed number to 32-bit signed number.
\r
220 int32_t extend_sign
\r
226 const uint32_t sign_bit_mask = 0x00008000u;
\r
228 y = (x ^ sign_bit_mask) - sign_bit_mask;
\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
237 uint32_t adjust_to_24bit_ace_format
\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
246 /* Check saturation. */
\r
247 if(signed48 > MAX_POSITIVE)
\r
249 signed48 = MAX_POSITIVE;
\r
251 else if(signed48 < MIN_NEGATIVE)
\r
253 signed48 = MIN_NEGATIVE;
\r
256 /* Adjust to 24-bit ACE format. */
\r
257 ace24_format = (uint32_t)(signed48 >> 14);
\r
259 return ace24_format;
\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
266 uint32_t adjust_to_16bit_ace_format
\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
275 /* Check saturation. */
\r
276 if(signed48 > MAX_POSITIVE)
\r
278 signed48 = MAX_POSITIVE;
\r
280 else if(signed48 < MIN_NEGATIVE)
\r
282 signed48 = MIN_NEGATIVE;
\r
285 /* Adjust to 24-bit ACE format. */
\r
286 ace24_format = (uint32_t)(signed48 >> 20);
\r
288 return ace24_format;
\r
291 /*-------------------------------------------------------------------------*//**
\r
294 void get_calibration
\r
296 adc_channel_id_t channel_id,
\r
297 channel_calibration_t * p_calibration
\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
304 const cal_channel_type_t channel_type_lut[16] =
\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
324 cal_channel_type_t channel_type;
\r
325 uint32_t channel_nb;
\r
329 mtd_calibration_mc_t const * p_mc_coeff = 0;
\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
335 quad_id = adc_nb * 2;
\r
337 if ( (channel_nb > 4) && (channel_nb < 9) ) { ++quad_id; }
\r
339 switch ( channel_type )
\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
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
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
359 { /* direct input */
\r
360 p_mc_coeff = &p_mtd_data->quads_direct_input_cal[quad_id][0];
\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
373 { /* direct input */
\r
374 p_mc_coeff = &p_mtd_data->quads_direct_input_cal[quad_id][1];
\r
379 case DIRECT_ADC_INPUT_CHAN:
\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
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
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
398 if (chopping_option > 0)
\r
400 chopping_option = 1;
\r
402 p_mc_coeff = &p_mtd_data->obd_calibration[adc_nb][obd_mode][chopping_option];
\r
406 case FLOATING_CHAN:
\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
414 if (p_mc_coeff != 0)
\r
416 p_calibration->m1 = p_mc_coeff->m;
\r
417 p_calibration->c1 = p_mc_coeff->c;
\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
425 if (g_ace_external_varef_used[adc_nb])
\r
427 p_calibration->mext = p_mtd_data->global_settings.varef_m;
\r
431 p_calibration->mext = NEUTRAL_M_FACTOR;
\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
442 void write_transform_coefficients
\r
444 ace_channel_handle_t channel_handle,
\r
449 uint16_t m_ppe_offset;
\r
450 uint16_t c_ppe_offset;
\r
451 const uint32_t PPE_OPCODE_MASK = 0xFF000000u;
\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
456 ACE->PPE_RAM_DATA[m_ppe_offset]
\r
457 = (ACE->PPE_RAM_DATA[m_ppe_offset] & PPE_OPCODE_MASK) | (m >> 8u);
\r
459 ACE->PPE_RAM_DATA[c_ppe_offset]
\r
460 = (ACE->PPE_RAM_DATA[c_ppe_offset] & PPE_OPCODE_MASK) | (c >> 8u);
\r
463 #endif /* ACE_CFG_DATA_FORMAT_VERSION */
\r