4 * Created on: 12.2.2013
8 * This file contains function for getting fray status as spi respons
9 * and functions for FlexRay initialization and usage.
10 * FlexRay chips on SPI are read only.
15 /** Prepared spi command */
16 uint32_t fray_spi_cmd = FRAY_SPICMD_INIT_VAL;
17 /** Shadow variable used during command sending */
18 uint32_t fray_spi_cmd_sh;
19 /** Array of responses for each fray driver */
20 uint32_t fray_spi_resp[FRAY_NUM_PORTS];
21 /** Array of port names to be easily accessible by indexing */
22 const char* fray_port_names[FRAY_NUM_PORTS] = { PORT_NAME_FRAY1, PORT_NAME_FRAY2 };
25 * @brief Function sends prepared command on SPI and stores response
27 * @param[in] port Index of flexray 0 or 1
28 * @return 0 when success, -1 when bad parameter
30 int fray_spi_transfer(uint8_t port) {
34 if (port > FRAY_NUM_PORTS) return -1;
35 desc = hal_port_get_dsc(fray_port_names[port], -1);
36 fray_spi_cmd_sh = fray_spi_cmd;
37 commands[0] = (fray_spi_cmd_sh & 0xFF00) >> 8;
38 commands[1] = (fray_spi_cmd_sh & 0xFF);
40 fray_spi_resp[port] = desc->port_setfnc_ptr(desc->config, desc->numValues, commands);
45 * @brief Returns last spi response of selected fray port
47 * @param[in] port Index of flexray 0 or 1
48 * @return spi response or -1 when bad parameter
50 int fray_spi_response(uint8_t port) {
51 if (port > FRAY_NUM_PORTS) return -1;
52 return fray_spi_resp[port];
56 * @brief Returns last spi command of selected fray port
58 * @param[in] port Index of flexray 0 or 1
59 * @return spi command or -1 when bad parameter
61 int fray_spi_get_cmd(uint8_t port) {
62 if (port > FRAY_NUM_PORTS) return -1;
66 /** @fn clear_msg_ram(void)
67 * @brief Clears FRAY message RAMs
69 * Send command to POC to set all bits of message RAM to 0.
70 * @return SUCCESS or FAILURE when command was not accepted
72 int fray_clear_msg_ram() {
73 fray_wait_for_POC_ready();
74 frayREG->SUCC1_UN.SUCC1_ST.cmd_B4 = CMD_CLEAR_RAMS;
75 if (frayREG->SUCC1_UN.SUCC1_ST.cmd_B4 == CMD_command_not_accepted)
77 fray_wait_for_POC_ready();
81 /** @fn wait_for_POC_ready(void)
82 * @brief Wait until POC is not busy
84 void fray_wait_for_POC_ready() {
85 // Wait for PBSY bit to clear - POC not busy.
86 // 1: Signals that the POC is busy and cannot accept a command from the host. CMD(3-0) is locked against write accesses.
87 while(((frayREG->SUCC1_UN.SUCC1_UL) & 0x00000080) != 0);
90 /** @fn fray_init(cfg *Fr_ConfigPtr)
91 * @brief Set global configuration
93 * Copy configuration filled in structure into config registers
94 * @param Fr_ConfigPtr Pointer to structure with configuration
96 void fray_init(const cfg *Fr_ConfigPtr)
98 frayREG->SUCC1_UN.SUCC1_UL = 0x0C401000; // Keep default value
99 frayREG->MRC_UN.MRC_UL = Fr_ConfigPtr->mrc;
100 frayREG->PRTC1_UN.PRTC1_UL = Fr_ConfigPtr->prtc1;
101 frayREG->PRTC2_UN.PRTC2_UL = Fr_ConfigPtr->prtc2;
102 frayREG->MHDC_UN.MHDC_UL = Fr_ConfigPtr->mhdc;
103 frayREG->GTUC1_UN.GTUC1_UL = Fr_ConfigPtr->gtu1;
104 frayREG->GTUC2_UN.GTUC2_UL = Fr_ConfigPtr->gtu2;
105 frayREG->GTUC3_UN.GTUC3_UL = Fr_ConfigPtr->gtu3;
106 frayREG->GTUC4_UN.GTUC4_UL = Fr_ConfigPtr->gtu4;
107 frayREG->GTUC5_UN.GTUC5_UL = Fr_ConfigPtr->gtu5;
108 frayREG->GTUC6_UN.GTUC6_UL = Fr_ConfigPtr->gtu6;
109 frayREG->GTUC7_UN.GTUC7_UL = Fr_ConfigPtr->gtu7;
110 frayREG->GTUC8_UN.GTUC8_UL = Fr_ConfigPtr->gtu8;
111 frayREG->GTUC9_UN.GTUC9_UL = Fr_ConfigPtr->gtu9;
112 frayREG->GTUC10_UN.GTUC10_UL = Fr_ConfigPtr->gtu10;
113 frayREG->GTUC11_UN.GTUC11_UL = Fr_ConfigPtr->gtu11;
114 frayREG->SUCC2_UN.SUCC2_UL = Fr_ConfigPtr->succ2;
115 frayREG->SUCC3_UN.SUCC3_UL = Fr_ConfigPtr->succ3;
116 frayREG->SUCC1_UN.SUCC1_ST.txst_B1 = 1;
117 frayREG->SUCC1_UN.SUCC1_ST.txsy_B1 = 1;
121 * Fill buffer configuration data structure with given data and transfer it to the message RAM header.
122 * @param[in] buf_num number of buffer to be configured (0-128)
123 * @param[in] mode Flag array for buffer configuration. Flags are defined in header file with prefix FRAY_BUF_
124 * @param[in] cyc_filter Setting for cycle filter. 0 - disabled
125 * @param[in] frame_id Id of the frame to be associated with the buffer
126 * @param[in] payload Maximum data size in half-word
127 * @param[in] data_pointer Address of the first word of data in buffer
129 void fray_config_buffer(uint32_t buf_num, uint8_t mode, uint32_t cyc_filter, uint32_t frame_id, uint32_t payload, uint32_t data_pointer) {
132 Fr_LPdu.mbi = (mode&FRAY_BUF_MBI_EN) ? 1 : 0; // message buffer interrupt
133 Fr_LPdu.txm = (mode&FRAY_BUF_TX_MODE_CONTINUOUS) ? 1 : 0; // transmission mode(0=continuous mode, 1=single mode)
134 Fr_LPdu.ppit = (mode&FRAY_BUF_NM_EN) ? 1 : 0; // network management Enable
135 Fr_LPdu.cfg = (mode&FRAY_BUF_TX) ? 1 : 0; // message buffer configuration bit (0=RX, 1 = TX)
136 Fr_LPdu.chb = (mode&FRAY_BUF_CHB_EN) ? 1 : 0; // Ch B
137 Fr_LPdu.cha = (mode&FRAY_BUF_CHA_EN) ? 1 : 0; // Ch A
138 Fr_LPdu.cyc = cyc_filter; // Cycle Filtering Code (no cycle filtering)
139 Fr_LPdu.fid = frame_id; // Frame ID
141 // Write Header Section 2 (WRHS2)
142 Fr_LPdu.pl = payload; // Payload Length
144 // Write Header Section 3 (WRHS3)
145 Fr_LPdu.dp = data_pointer; // Pointer to start of data in message RAM
147 Fr_LPdu.sfi = (mode&FRAY_BUF_SFI_EN) ? 1 : 0; // startup frame indicator
148 Fr_LPdu.sync = (mode&FRAY_BUF_SYNC_EN) ? 1 : 0; // sync frame indicator
150 // Write Header Section 2 (WRHS2)
151 Fr_LPdu.crc = (mode&FRAY_BUF_TX) ? fray_header_crc_calc(&Fr_LPdu) : 0;
153 // Input buffer configuration
154 Fr_LSdu.ibrh = buf_num; // input buffer number
155 Fr_LSdu.ibsyh = 1; // check for input buffer busy host
156 Fr_LSdu.ibsys = 1; // check for input buffer busy shadow
158 Fr_LSdu.stxrh= 0; // set transmission request
159 Fr_LSdu.ldsh = 0; // load data section
160 Fr_LSdu.lhsh = 1; // load header section
161 Fr_LSdu.obrs = 0; // output buffer number
162 Fr_LSdu.rdss = 0; // read data section
163 Fr_LSdu.rhss = 0; // read header section
165 fray_prepare_LPdu(&Fr_LPdu);
166 fray_transmit_tx_LPdu(&Fr_LSdu);
170 * Initialize POC. At first go to CONFIG state, then run the unlock sequence
171 * and at the end go to READY state
172 * @return SUCCESS or FAILURE
174 int fray_controler_init() {
175 unsigned int error=SUCCESS;
176 // write SUCC1 configuration
177 frayREG->SUCC1_UN.SUCC1_UL = 0x0F1FFB00 | CMD_CONFIG;
178 // Check if POC has accepted last command
179 if ((frayREG->SUCC1_UN.SUCC1_UL & 0xF) == 0x0) return 1;
180 // Wait for PBSY bit to clear - POC not busy
181 fray_wait_for_POC_ready();
183 // unlock CONFIG and enter READY state
184 frayREG->LCK_UN.LCK_ST.clk_B8=0xCE;
185 frayREG->LCK_UN.LCK_ST.clk_B8=0x31;
186 // write SUCC1 configuration
187 frayREG->SUCC1_UN.SUCC1_ST.cmd_B4=(0xFB00 | CMD_READY);
188 // Check if POC has accepted last command
189 if ((frayREG->SUCC1_UN.SUCC1_UL & 0xF) == 0x0) error = FAILURE;
190 // Wait for PBSY bit to clear - POC not busy
191 fray_wait_for_POC_ready();
197 * Enable CYCSE interrupt
198 * Clear Errors and statuses
200 void fray_init_irq() {
201 frayREG->EIR_UN.EIR_UL = 0xFFFFFFFF; // Clear Error Int.
202 frayREG->SIR_UN.SIR_UL = 0xFFFFFFFF; // Clear Status Int.
203 frayREG->SILS_UN.SILS_UL = 0x00000000; // all Status Int. to eray_int0
204 frayREG->SIER_UN.SIER_UL = 0xFFFFFFFF; // Disable all Status Int.
205 frayREG->SIES_UN.SIES_UL = 0x00000004; // Enable CYCSE Int.
206 frayREG->ILE_UN.ILE_UL = 0x00000002; // enable eray_int1
210 * Load data to message buffer.
211 * @param[in] buf_num Number of buffer
212 * @param[in] data Pointer to data array
213 * @param[in] len Number of words to be loaded from data to buffer
215 void fray_buffer_set_data(uint32_t buf_num, const uint32_t* data, uint32_t len) {
219 write_buffer.ibrh = buf_num; // input buffer number
220 write_buffer.stxrh= 1; // set transmission request
221 write_buffer.ldsh = 1; // load data section
222 write_buffer.lhsh = 0; // load header section
223 write_buffer.ibsys = 0; // check for input buffer busy shadow
224 write_buffer.ibsyh = 1; // check for input buffer busy host
225 for (i = 0; i < len; i++) {
226 frayREG->WRDS[i] = data[i];
228 fray_transmit_tx_LPdu(&write_buffer);
232 * Retrieve data from message buffer.
233 * @param[in] buf_num Number of buffer
234 * @param[out] data Pointer to array, where retrieved data will be stored.
235 * @param[in] len Number of words to be loaded from data to buffer
237 void fray_buffer_get_data(uint32_t buf_num, uint32_t* data, uint32_t len) {
241 read_buffer.obrs=buf_num; // output buffer number
242 read_buffer.rdss=1; // read data section
243 read_buffer.rhss=0; // read header section
244 fray_receive_rx_LPdu(&read_buffer);
245 for (i = 0; i < len; i++) {
246 data[i] = frayREG->RDDS[i];
252 * Wait for interrupt flag, that new communication cycle started
253 * Clears status flags
255 void fray_wait_for_new_cycle() {
256 frayREG->SIR_UN.SIR_UL = 0xFFFFFFFF; // clear all status int. flags
257 while ((frayREG->SIR_UN.SIR_UL & 0x4) == 0x0); // wait for CYCS interrupt flag
258 frayREG->SIR_UN.SIR_UL = 0xFFFFFFFF; // clear all status int. flags
262 * Check if some new message was received to the message buffer.
263 * @param[in] buf_num Number of the buffer to be checked
264 * @return 1 when new message is available, otherwise 0
266 int fray_buffer_message_received(uint32_t buf_num) {
270 ndat = frayREG->NDAT1_UN.NDAT1_UL;
273 else if (buf_num < 64) {
274 ndat = frayREG->NDAT2_UN.NDAT2_UL;
275 offset = buf_num - 32;
277 else if (buf_num < 96) {
278 ndat = frayREG->NDAT3_UN.NDAT3_UL;
279 offset = buf_num - 64;
281 else if (buf_num < 128) {
282 ndat = frayREG->NDAT4_UN.NDAT4_UL;
283 offset = buf_num - 96;
289 return (ndat&(1<<offset));
293 * Process the FlexRay startup procedure according diagrams in FlexRay protocol specification.
294 * @param[in] is_coldstar Specifies if node is coldstart or if it can be just integrated to existing network
295 * @return SUCCESS or error code
297 int fray_startup_procedure(int is_coldstart) {
299 uint32_t state_value;
303 ok = fray_go_to_ready_state_from_config_state();
305 return FRAY_ERR_SW_CFG_READY; // Switching to ready state error
313 // try as following cold starter
314 ok = fray_go_to_startup_state();
316 return FRAY_ERR_SW_STUP_FOLLOW; // Switch to run error
318 // Wait until NORMAL_ACTIVE state or timeout
320 state_value = frayREG->CCSV_UN.CCSV_ST.pocs_B6;
322 } while ((state_value != 0x02) && (counter < 10000000U));
324 // No success in integration
325 if (frayREG->CCSV_UN.CCSV_ST.pocs_B6 == 0x27){
326 csa = frayREG->CCSV_UN.CCSV_ST.rca_B5;
327 // Some cold starts attempts remains
329 // Try allow cold start
330 ok = fray_allow_coldstart();
332 return FRAY_ERR_CSINH_DIS; // Cold start inhibit disabled error
337 // Wait until NORMAL_ACTIVE or INTEGRATION_LISTEN state
339 state_value = frayREG->CCSV_UN.CCSV_ST.pocs_B6;
340 } while ( (state_value != 0x02) && (state_value != 0x27));
342 // Success, break the start up loop
343 if (frayREG->CCSV_UN.CCSV_ST.pocs_B6 == 0x02)
346 // No success. Switch back to READY state
348 ok = fray_go_to_ready_state_from_startup_state();
350 return FRAY_ERR_SW_STUP_READY; // Switch to READY failed
354 // Non-cold start branch
356 ok = fray_go_to_startup_state();
358 return FRAY_ERR_SW_STUP_AS_NCOLD; // Switching to startup state as non-cold start node
361 // Wait until NORMAL_ACTIVE
363 state_value = frayREG->CCSV_UN.CCSV_ST.pocs_B6;
364 } while (state_value != 0x02);
373 /** @fn go_to_ready_state_from_config_state(void)
374 * @brief Set POC command
376 * Send command to POC to switch into READY state.
377 * @return SUCCESS or FAILURE
379 int fray_go_to_ready_state_from_config_state(void) {
380 fray_wait_for_POC_ready();
382 if (frayREG->SUCC1_UN.SUCC1_ST.ccha_B1 && frayREG->SUCC1_UN.SUCC1_ST.cchb_B1){
384 frayREG->LCK_UN.LCK_ST.clk_B8 = 0xCE;
385 frayREG->LCK_UN.LCK_ST.clk_B8 = 0x31;
386 frayREG->SUCC1_UN.SUCC1_ST.cmd_B4 = CMD_READY;
388 frayREG->LCK_UN.LCK_ST.clk_B8 = 0xCE;
389 frayREG->LCK_UN.LCK_ST.clk_B8 = 0x31;
390 frayREG->SUCC1_UN.SUCC1_ST.mtsa_B1 = 1U;
392 frayREG->LCK_UN.LCK_ST.clk_B8 = 0xCE;
393 frayREG->LCK_UN.LCK_ST.clk_B8 = 0x31;
394 frayREG->SUCC1_UN.SUCC1_ST.mtsb_B1 = 1U;
396 else if(frayREG->SUCC1_UN.SUCC1_ST.ccha_B1){
398 frayREG->LCK_UN.LCK_ST.clk_B8 = 0xCE;
399 frayREG->LCK_UN.LCK_ST.clk_B8 = 0x31;
400 frayREG->SUCC1_UN.SUCC1_ST.cmd_B4 = CMD_READY;
402 frayREG->LCK_UN.LCK_ST.clk_B8 = 0xCE;
403 frayREG->LCK_UN.LCK_ST.clk_B8 = 0x31;
404 frayREG->SUCC1_UN.SUCC1_ST.mtsa_B1 = 1U;
406 else if (frayREG->SUCC1_UN.SUCC1_ST.cchb_B1){
408 frayREG->LCK_UN.LCK_ST.clk_B8 = 0xCE;
409 frayREG->LCK_UN.LCK_ST.clk_B8 = 0x31;
410 frayREG->SUCC1_UN.SUCC1_ST.cmd_B4 = CMD_READY;
412 frayREG->LCK_UN.LCK_ST.clk_B8 = 0xCE;
413 frayREG->LCK_UN.LCK_ST.clk_B8 = 0x31;
414 frayREG->SUCC1_UN.SUCC1_ST.mtsb_B1 = 1U;
416 else frayREG->SUCC1_UN.SUCC1_ST.cmd_B4 = CMD_READY;
418 if (frayREG->SUCC1_UN.SUCC1_ST.cmd_B4 == CMD_command_not_accepted)
420 while ((frayREG->CCSV_UN.CCSV_UL & 0x0000003F) != 0x01)
421 ; //cekam dokud POC neni v ready stavu
425 /** @fn go_to_ready_state_from_startup_state(void)
426 * @brief Set POC command
428 * Send command to POC to switch into READY state.
429 * @return SUCCESS or FAILURE
431 int fray_go_to_ready_state_from_startup_state(void){
432 fray_wait_for_POC_ready();
433 frayREG->SUCC1_UN.SUCC1_ST.cmd_B4 = CMD_READY;
434 if (frayREG->SUCC1_UN.SUCC1_ST.cmd_B4 == CMD_command_not_accepted) return (FAILURE);
435 while ((frayREG->CCSV_UN.CCSV_UL & 0x0000003F) != 0x01); //cekam dokud POC neni v ready stavu
439 /** @fn go_to_startup_state(void)
440 * @brief Set POC command
442 * Send command to POC to switch into RUN state.
443 * @return SUCCESS or FAILURE
445 int fray_go_to_startup_state(void) {
446 fray_wait_for_POC_ready();
447 frayREG->SUCC1_UN.SUCC1_ST.cmd_B4 = CMD_RUN;
448 if (frayREG->SUCC1_UN.SUCC1_ST.cmd_B4 == CMD_command_not_accepted)
453 /** @fn allow_coldstart(void)
454 * @brief Allows cold start
456 * Send command to erase coldstart inhibit flag.
457 * This allows the node to start as coldstart node.
458 * @return SUCCESS or FAILURE
460 int fray_allow_coldstart(void) {
461 fray_wait_for_POC_ready();
462 frayREG->SUCC1_UN.SUCC1_ST.cmd_B4 = CMD_ALLOW_COLDSTART;
463 if (frayREG->SUCC1_UN.SUCC1_ST.cmd_B4 == CMD_command_not_accepted)
469 * FlexRay delay used while network initiation.
471 * !This is busy waiting!
473 void fray_delay(void) {
474 volatile uint32_t delayval;
476 delayval = 375000; // 100000 are about 10ms
477 while(delayval-- > 0 )
481 /** @fn send_halt_command
482 * @brief Send HALT command
484 * Send command to the node to stop its activity after the end of
486 * @return SUCCESS or FAILURE
488 int fray_halt(void) {
489 fray_wait_for_POC_ready();
490 frayREG->SUCC1_UN.SUCC1_ST.cmd_B4 = 6U;
491 if (frayREG->SUCC1_UN.SUCC1_ST.cmd_B4 == CMD_command_not_accepted)
497 * Compute CRC for message RAM header data
498 * @param[in] Fr_LPduPtr Pointer to header data
501 int fray_header_crc_calc(const wrhs *Fr_LPduPtr) {
507 unsigned long CrcPoly = 0x385;
508 unsigned long CrcReg_X = CrcInit;
509 unsigned long header_temp, reg_temp;
511 header = ((Fr_LPduPtr->sync & 0x1) << 19) | ((Fr_LPduPtr->sfi & 0x1) << 18);
512 header |= ((Fr_LPduPtr->fid & 0x7FF) << 7) | (Fr_LPduPtr->pl & 0x7F);
520 header_temp = header & 0x80000000;
521 reg_temp = CrcReg_X & 0x80000000;
523 if(header_temp ^ reg_temp){ // Step 1
529 CrcReg_X <<= 1; // Step 2
532 CrcReg_X ^= CrcPoly; // Step 3
542 * Prepare data to be transmitted to message RAM by input buffer,
543 * @param[in] Fr_LPduPtr Pointer to data structure to be send
545 void fray_prepare_LPdu(const wrhs *Fr_LPduPtr) {
548 wrhs1 = ((Fr_LPduPtr->mbi) & 0x1) <<29;
549 wrhs1 |= (Fr_LPduPtr->txm & 0x1) << 28;
550 wrhs1 |= (Fr_LPduPtr->ppit & 0x1) << 27;
551 wrhs1 |= (Fr_LPduPtr->cfg & 0x1) << 26;
552 wrhs1 |= (Fr_LPduPtr->chb & 0x1) << 25;
553 wrhs1 |= (Fr_LPduPtr->cha & 0x1) << 24;
554 wrhs1 |= (Fr_LPduPtr->cyc & 0x7F) << 16;
555 wrhs1 |= (Fr_LPduPtr->fid & 0x7FF);
556 frayREG->WRHS1_UN.WRHS1_UL = wrhs1;
558 wrhs2 = ((Fr_LPduPtr->pl & 0x7F) << 16) | (Fr_LPduPtr->crc & 0x7FF);
559 frayREG->WRHS2_UN.WRHS2_UL = wrhs2;
561 frayREG->WRHS3_UN.WRHS3_UL = (Fr_LPduPtr->dp & 0x7FF);
565 * Transfer data from input buffer to message RAM
566 * @param[in] Fr_LSduPtr Pointer to data structure with input buffer settings
568 void fray_transmit_tx_LPdu(const bc *Fr_LSduPtr) {
569 // ensure nothing is pending
570 while ((frayREG->IBCR_UN.IBCR_UL & 0x0008000) != 0);
571 frayREG->IBCM_UN.IBCM_UL=((Fr_LSduPtr->stxrh & 0x1) << 2) | ((Fr_LSduPtr->ldsh & 0x1) << 1) | (Fr_LSduPtr->lhsh & 0x1);
572 frayREG->IBCR_UN.IBCR_UL=(Fr_LSduPtr->ibrh & 0x3F);
573 // optimization possible for future by not gating like below
574 // wait for completion on host registers
575 while ((Fr_LSduPtr->ibsyh != 0) && ((frayREG->IBCR_UN.IBCR_UL & 0x00008000) != 0));
576 // wait for completion on shadow registers
577 while ((Fr_LSduPtr->ibsys != 0) && ((frayREG->IBCR_UN.IBCR_UL & 0x80000000) != 0));
581 * Receive data from message buffer into output buffer.
582 * @param[in] Fr_LSduPtr Pointer to data structure with output buffer settings
584 void fray_receive_rx_LPdu(const bc *Fr_LSduPtr) {
585 // ensure no transfer in progress on shadow registers
586 while (((frayREG->OBCR_UN.OBCR_UL) & 0x00008000) != 0);
587 frayREG->OBCM_UN.OBCM_UL=(((Fr_LSduPtr->rdss & 0x1) << 1) | (Fr_LSduPtr->rhss & 0x1));
588 frayREG->OBCR_UN.OBCR_UL=((1 << 9) | (Fr_LSduPtr->obrs & 0x3F)); //req=1, view=0
589 // wait for completion on shadow registers
590 while (((frayREG->OBCR_UN.OBCR_UL) & 0x00008000) != 0);
592 frayREG->OBCM_UN.OBCM_UL=(((Fr_LSduPtr->rdss & 0x1) << 1) | (Fr_LSduPtr->rhss & 0x1));
593 frayREG->OBCR_UN.OBCR_UL=((1 << 8) | (Fr_LSduPtr->obrs & 0x3F)); //req=0, view=1