• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "hpm_lin_drv.h"
9 
10 #define HPM_LIN_DRV_RETRY_COUNT (50000U)
11 
lin_master_configure_timing(LIN_Type * ptr,lin_timing_t * timing)12 hpm_stat_t lin_master_configure_timing(LIN_Type *ptr, lin_timing_t *timing)
13 {
14     assert(timing->src_freq_in_hz >= 8000000U);
15     assert((timing->baudrate >= 1000U) && (timing->baudrate <= 20000U));
16 
17     uint8_t prescaler, bt_mul;
18     uint16_t bt_div;
19 
20     /** set master mode */
21     ptr->TV |= LIN_TV_MASTER_MODE_MASK;
22     ptr->TV |= LIN_TV_INITIAL_MODE_MASK;
23     ptr->TV &= ~LIN_TV_INITIAL_MODE_MASK;
24 
25     bt_mul = 20000U / timing->baudrate - 1U;
26     prescaler = log((timing->src_freq_in_hz / ((bt_mul + 1U) * timing->baudrate * 200U))) / log(2U) - 1U;
27     bt_div = timing->src_freq_in_hz / ((1U << (prescaler + 1U)) * (bt_mul + 1U) * timing->baudrate);
28 
29     if ((bt_div < 200) || (bt_div > 512)) {
30         return status_invalid_argument;
31     }
32 
33     /** src =20MHz baudrate = 19.2KHz */
34     /** bt_div = 260, scaler = 1, bt_mul = 0 */
35     ptr->BAUDRATE_CTL_LOW = bt_div & 0xFF;
36     ptr->BARDRATE_CTL_HIGH = LIN_BARDRATE_CTL_HIGH_BT_DIV_HIGH_SET(bt_div >> 8U)
37                              | LIN_BARDRATE_CTL_HIGH_BT_MUL_SET(bt_mul)
38                              | LIN_BARDRATE_CTL_HIGH_PRESCL_SET(prescaler);
39 
40     return status_success;
41 }
42 
lin_slave_configure_timing(LIN_Type * ptr,uint32_t src_freq_in_hz)43 hpm_stat_t lin_slave_configure_timing(LIN_Type *ptr, uint32_t src_freq_in_hz)
44 {
45     assert(src_freq_in_hz >= 8000000U);
46 
47     uint8_t prescaler;
48     uint16_t bt_div;
49 
50     /** set slave mode */
51     ptr->TV &= ~LIN_TV_MASTER_MODE_MASK;
52     ptr->TV |= LIN_TV_INITIAL_MODE_MASK;
53     ptr->TV &= ~LIN_TV_INITIAL_MODE_MASK;
54 
55     prescaler = log((src_freq_in_hz / (20000U * 200U))) / log(2U) - 1U;
56     bt_div = src_freq_in_hz / ((1U << (prescaler + 1U)) * 20000U);
57 
58     if ((bt_div < 200) || (bt_div > 512)) {
59         return status_invalid_argument;
60     }
61 
62     /** src = 20MHz, prescaler = 1, bt_div = 250 */
63     ptr->BAUDRATE_CTL_LOW = bt_div & 0xFF;
64     ptr->BARDRATE_CTL_HIGH = LIN_BARDRATE_CTL_HIGH_BT_DIV_HIGH_SET(bt_div >> 8U)
65                              | LIN_BARDRATE_CTL_HIGH_PRESCL_SET(prescaler);
66 
67     return status_success;
68 }
69 
lin_get_data_length_from_id(uint8_t id)70 uint8_t lin_get_data_length_from_id(uint8_t id)
71 {
72     switch (LIN_ID_DATA_LEN_GET(id)) {
73     case id_data_length_2bytes:
74         return 2;
75     case id_data_length_2bytes_2:
76         return 2;
77     case id_data_length_4bytes:
78         return 4;
79     case id_data_length_8bytes:
80         return 8;
81     default:
82         return 8;
83     }
84 }
85 
lin_get_data_length(LIN_Type * ptr)86 uint8_t lin_get_data_length(LIN_Type *ptr)
87 {
88     uint8_t data_length = 0;
89     if (((ptr->DATA_LEN) & LIN_DATA_LEN_DATA_LENGTH_MASK) == LIN_DATA_LEN_DATA_LENGTH_MASK) {
90         data_length = lin_get_data_length_from_id(ptr->ID);
91     } else {
92         data_length = LIN_DATA_LEN_DATA_LENGTH_GET(ptr->DATA_LEN);
93     }
94     return data_length;
95 }
96 
lin_master_transfer(LIN_Type * ptr,lin_trans_config_t * config)97 void lin_master_transfer(LIN_Type *ptr, lin_trans_config_t *config)
98 {
99     uint8_t data_length;
100 
101     ptr->ID = config->id;
102 
103     if (config->data_length_from_id) {
104         data_length = lin_get_data_length_from_id(ptr->ID);
105         ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_MASK;
106     } else {
107         data_length = config->data_length;
108         ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_SET(data_length);
109     }
110 
111     /** sent or receive */
112     ptr->CONTROL = 0U;
113     if (config->transmit) {
114         ptr->CONTROL = LIN_CONTROL_TRANSMIT_MASK;
115     }
116 
117     if (config->transmit) {
118         for (uint8_t i = 0; i < data_length; i++) {
119             ptr->DATABYTE[i] = *((config->data_buff)++);
120         }
121     }
122 
123     /** start */
124     ptr->CONTROL |= LIN_CONTROL_START_REQ_MASK;
125 }
126 
lin_master_sent(LIN_Type * ptr,lin_trans_config_t * config)127 hpm_stat_t lin_master_sent(LIN_Type *ptr, lin_trans_config_t *config)
128 {
129     uint32_t retry = 0;
130     uint8_t data_length = 0;
131 
132     /** lin active */
133     while (((ptr->STATE & LIN_STATE_LIN_ACTIVE_MASK) == LIN_STATE_LIN_ACTIVE_MASK)) {
134         if (retry > HPM_LIN_DRV_RETRY_COUNT) {
135             break;
136         }
137         retry++;
138     }
139 
140     if (retry > HPM_LIN_DRV_RETRY_COUNT) {
141         return status_timeout;
142     }
143 
144     ptr->ID = config->id;
145 
146     if (config->data_length_from_id) {
147         data_length = lin_get_data_length_from_id(ptr->ID);
148         ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_MASK;
149     } else {
150         data_length = config->data_length;
151         ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_SET(data_length);
152     }
153 
154     ptr->CONTROL = LIN_CONTROL_TRANSMIT_MASK;
155 
156     /** load data into registers */
157     for (uint8_t i = 0; i < data_length; i++) {
158         ptr->DATABYTE[i] = *((config->data_buff)++);
159     }
160 
161     /** start */
162     ptr->CONTROL |= LIN_CONTROL_START_REQ_MASK;
163 
164     /**  lin complete */
165     retry = 0;
166     while (!((ptr->STATE & LIN_STATE_COMPLETE_MASK) == LIN_STATE_COMPLETE_MASK)) {
167         if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
168             break;
169         }
170         retry++;
171     }
172 
173     if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
174         return status_timeout;
175     }
176     return status_success;
177 }
178 
lin_master_receive(LIN_Type * ptr,lin_trans_config_t * config)179 hpm_stat_t lin_master_receive(LIN_Type *ptr, lin_trans_config_t *config)
180 {
181     uint32_t retry = 0;
182     uint8_t data_length;
183 
184     /** lin active */
185     while (((ptr->STATE & LIN_STATE_LIN_ACTIVE_MASK) == LIN_STATE_LIN_ACTIVE_MASK)) {
186         if (retry > HPM_LIN_DRV_RETRY_COUNT) {
187             break;
188         }
189         retry++;
190     }
191 
192     if (retry > HPM_LIN_DRV_RETRY_COUNT) {
193         return status_timeout;
194     }
195 
196     ptr->ID = config->id;
197 
198     if (config->data_length_from_id) {
199         data_length = lin_get_data_length_from_id(ptr->ID);
200         ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_MASK;
201     } else {
202         data_length = config->data_length;
203         ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_SET(data_length);
204     }
205 
206     /** receive */
207     ptr->CONTROL = 0U;
208     /** start */
209     ptr->CONTROL |= LIN_CONTROL_START_REQ_MASK;
210 
211     /** waiting for receive complete */
212     retry = 0;
213     while (!((ptr->STATE & LIN_STATE_COMPLETE_MASK) == LIN_STATE_COMPLETE_MASK)) {
214         if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
215             break;
216         }
217         retry++;
218     }
219 
220     if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
221         return status_fail;
222     }
223 
224     /** load register data into buffer */
225     for (uint8_t i = 0; i < data_length; i++) {
226         *((config->data_buff)++) = ptr->DATABYTE[i];
227     }
228 
229     return status_success;
230 }
231 
lin_slave_transfer(LIN_Type * ptr,lin_trans_config_t * config)232 void lin_slave_transfer(LIN_Type *ptr, lin_trans_config_t *config)
233 {
234     uint8_t data_length;
235 
236     /** transmit or receive */
237     ptr->CONTROL = LIN_CONTROL_TRANSMIT_SET(config->transmit);
238 
239     if (config->data_length_from_id) {
240         data_length = lin_get_data_length_from_id(ptr->ID);
241         ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_MASK;
242     } else {
243         data_length = config->data_length;
244         ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_SET(data_length);
245     }
246 
247     if (config->transmit) {
248         for (uint8_t i = 0; i < data_length; i++) {
249             ptr->DATABYTE[i] = *((config->data_buff)++);
250         }
251     }
252 
253     /** data ack */
254     ptr->CONTROL |= LIN_CONTROL_DATA_ACK_MASK;
255 }
256 
lin_slave_sent(LIN_Type * ptr,lin_trans_config_t * config)257 hpm_stat_t lin_slave_sent(LIN_Type *ptr, lin_trans_config_t *config)
258 {
259     uint32_t retry = 0;
260     uint8_t data_length;
261 
262     /** lin data_req */
263     /** lin active? */
264     while (((ptr->STATE & LIN_STATE_DATA_REQ_MASK) == LIN_STATE_DATA_REQ_MASK)) {
265         if (retry > HPM_LIN_DRV_RETRY_COUNT) {
266             break;
267         }
268         retry++;
269     }
270 
271     if (retry > HPM_LIN_DRV_RETRY_COUNT) {
272         return status_timeout;
273     }
274 
275     /** transmit */
276     ptr->CONTROL = LIN_CONTROL_TRANSMIT_MASK;
277 
278     if (config->data_length_from_id) {
279         data_length = lin_get_data_length_from_id(ptr->ID);
280         ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_MASK;
281     } else {
282         data_length = config->data_length;
283         ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_SET(data_length);
284     }
285 
286     for (uint8_t i = 0; i < data_length; i++) {
287         ptr->DATABYTE[i] = *((config->data_buff)++);
288     }
289 
290     /** data ack */
291     ptr->CONTROL |= LIN_CONTROL_DATA_ACK_MASK;
292 
293     /** lin complete */
294     retry = 0;
295     while (!((ptr->STATE & LIN_STATE_COMPLETE_MASK) == LIN_STATE_COMPLETE_MASK)) {
296         if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
297             break;
298         }
299         retry++;
300     }
301 
302     if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
303         return status_timeout;
304     }
305     return status_success;
306 }
307 
lin_slave_receive(LIN_Type * ptr,lin_trans_config_t * config)308 hpm_stat_t lin_slave_receive(LIN_Type *ptr, lin_trans_config_t *config)
309 {
310     uint32_t retry = 0;
311     uint8_t data_length;
312 
313     /** lin data_req */
314     while (((ptr->STATE & LIN_STATE_DATA_REQ_MASK) == LIN_STATE_DATA_REQ_MASK)) {
315         if (retry > HPM_LIN_DRV_RETRY_COUNT) {
316             break;
317         }
318         retry++;
319     }
320 
321     if (retry > HPM_LIN_DRV_RETRY_COUNT) {
322         return status_timeout;
323     }
324 
325     /** receive */
326     ptr->CONTROL = 0U;
327 
328     if (config->data_length_from_id) {
329         data_length = lin_get_data_length_from_id(ptr->ID);
330         ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_MASK;
331     } else {
332         data_length = config->data_length;
333         ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_SET(data_length);
334     }
335 
336     /** data ack */
337     ptr->CONTROL |= LIN_CONTROL_DATA_ACK_MASK;
338 
339     /** lin complete */
340     retry = 0;
341     while (!((ptr->STATE & LIN_STATE_COMPLETE_MASK) == LIN_STATE_COMPLETE_MASK)) {
342         if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
343             break;
344         }
345         retry++;
346     }
347 
348     if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
349         return status_timeout;
350     }
351 
352     for (uint8_t i = 0; i < data_length; i++) {
353         *((config->data_buff)++) = ptr->DATABYTE[i];
354     }
355 
356     return status_success;
357 }
358