Skip to content
Amin edited this page Jul 17, 2016 · 8 revisions

function.c

inline void wireless_connection ( void )

In this function we both receive new data from wireless board and send debug and monitoring data to it.This function is called in ISR(PORTD_INT0_vect) in main.c which is an external interrupt handler. It first gets the status of nRF24l01. nRF24l01 in robots operate in PRX mode. PRX stands for primary receiver. In this mode the most important bit in status register is _RX_DR.

When nRF24l01 receives a new packet of data it sets the _RX_DR and making an interrupt request by pulling down the IRQ line which is connected to pin 2 of PORTD. Then ISR(PORTD_INT0_vect) executes which calls wireless_connection ( ).

In wireless_connection ( ) we check _RX_DR bit and if it is set, get new packet -> NRF24L01_Read_RX_Buf(spi_rx_buf, _Buffer_Size);

Warning : Reading status bit _RX_DR

clears it which is necessary for next interrupt request from nRF24l01.

TODO : Last if statement is not needed(?).

inline void wireless_connection ( void )

{

 uint8_t status_L = NRF24L01_WriteReg(W_REGISTER | STATUSe, _TX_DS|_MAX_RT|_RX_DR);

 if((status_L & _RX_DR) == _RX_DR)

 {

 ioport_set_value(LED_WHITE, high);

 WIRLESS_TIMEOUT_TIMER = 0;

 wdt_reset();

 //! read payload through SPI,

 NRF24L01_Read_RX_Buf(spi_rx_buf, _Buffer_Size);

 free_wheel.wireless_timeout = false ;

 if(spi_rx_buf[0] == RobotID )

 {

 ioport_set_value(LED_RED, high);

 Robot.RID = spi_rx_buf[0];

 Robot.Vx_sp.byte[high] = spi_rx_buf[1];

 Robot.Vx_sp.byte[low] = spi_rx_buf[2];

 Robot.Vy_sp.byte[high] = spi_rx_buf[3];

 Robot.Vy_sp.byte[low] = spi_rx_buf[4];

 Robot.Wr_sp.byte[high] = spi_rx_buf[5];

 Robot.Wr_sp.byte[low] = spi_rx_buf[6];

 Robot.Vx.byte[high] = spi_rx_buf[7];

 Robot.Vx.byte[low] = spi_rx_buf[8];

 Robot.Vy.byte[high] = spi_rx_buf[9];

 Robot.Vy.byte[low] = spi_rx_buf[10];

 Robot.Wr.byte[high] = spi_rx_buf[11];

 Robot.Wr.byte[low] = spi_rx_buf[12];

 Robot.alpha.byte[high] = spi_rx_buf[13];

 Robot.alpha.byte[low] = spi_rx_buf[14];

 Robot.KICK = spi_rx_buf[15];

 Robot.CHIP = spi_rx_buf[16];

 /*Robot.SPIN*/Robot.orc_length = spi_rx_buf[17];//! test !!!!!!!!!!

 NRF24L01_Write_TX_Buf(spi_tx_buf, _Buffer_Size);

 signal_strength++;

 }

 }

 if ((status_L&_MAX_RT) == _MAX_RT)

 {

 NRF24L01_Flush_TX();

 }

}

inline void data_transmission (void)

In this function we transmit all monitoring data to nRF24l01 to be sent to Wireless board.

TODO : Using DMA

inline void data_transmission (void)

{

 HL show[16];

 show[0].full = cycle_time_us ;

 show[1].full = free_wheel.wireless_timeout;

 show[2].full = free_wheel.motor_fault;

 show[3].full = free_wheel.low_battery;

 show[4].full = Robot.ct;

 show[5].full = Robot.nsp;

 show[6].full = Robot.nrp;

 show[7].full = Robot.ss;

 show[8].full = bbs.lko;

 show[9].full = Robot.wrc;

 show[10].full = Robot.MCU_temperature.full ;

 show[11].full = (int)(Robot.I0.full*1000) ;

 show[12].full = (int)(Robot.I1.full*1000) ;

 show[13].full = (int)(Robot.I2.full*1000) ;

 show[14].full = (int)(Robot.I3.full*1000) ;

 //! Debug data

 spi_tx_buf[0] = show[0].byte[high];//

 spi_tx_buf[1] = show[0].byte[low]; //

 spi_tx_buf[2] = show[1].byte[high];//

 spi_tx_buf[3] = show[1].byte[low]; //

 spi_tx_buf[4] = show[2].byte[high];//

 spi_tx_buf[5] = show[2].byte[low]; //

 spi_tx_buf[6] = show[3].byte[high];//

 spi_tx_buf[7] = show[3].byte[low]; //

 //! Monitoring data

 spi_tx_buf[8] = show[4].byte[high];

 spi_tx_buf[9] = show[4].byte[low];

 spi_tx_buf[10] = show[5].byte[high];

 spi_tx_buf[11] = show[5].byte[low];

 spi_tx_buf[12] = show[6].byte[high];

 spi_tx_buf[13] = show[6].byte[low];

 spi_tx_buf[14] = show[7].byte[high];

 spi_tx_buf[15] = show[7].byte[low];

 spi_tx_buf[16] = show[8].byte[high];

 spi_tx_buf[17] = show[8].byte[low];

 spi_tx_buf[18] = show[9].byte[high];

 spi_tx_buf[19] = show[9].byte[low];

 spi_tx_buf[20] = show[10].byte[high];

 spi_tx_buf[21] = show[10].byte[low];

 spi_tx_buf[22] = show[11].byte[high];

 spi_tx_buf[23] = show[11].byte[low];

 spi_tx_buf[24] = show[12].byte[high];

 spi_tx_buf[25] = show[12].byte[low];

 spi_tx_buf[26] = show[13].byte[high];

 spi_tx_buf[27] = show[13].byte[low];

 spi_tx_buf[28] = show[14].byte[high];

 spi_tx_buf[29] = show[14].byte[low];

 spi_tx_buf[30] = Robot.batx1000.byte[high];

 spi_tx_buf[31] = Robot.batx1000.byte[low];

}

inline void data_packing ( void )

data_packing packs five words (2 bytes length) into a packet. These words are duty cycles which controller generates for each motor. Lack of enough connection line between SPARTAN3 and ATxmega64 (there is 15 lines) made us to use a 7 bit communication protocol in both direction. Last line is for synchronizing SPARTAN3 and ATxmega64 (clock line). In this protocol we cut last bit from each byte and make a new 7-bit data from cut bits. There is five payload words, and two checksum words, generated from payload, so the will be 5+2 words. So there is 14 bytes and it yields 14[byte] * 8[bit] / 7[bit] = 16 of 7-bit data type. In addition of payloads and checksum, there is two 7-bit preambles (start sign) at the beginning of packet.

7-bits that should be sent are placed in even rooms of an array. 7-bits that should be received will be placed in odd rooms of another array.

inline void data_packing ( void )

{

 HL MAKsumA ;

 HL MAKsumB ;

 //Robot.W0_sp.full = 1000;//test !!!!!!!!!!!!!!!!!!!!!!!!!

 //Robot.W1_sp.full = 1000;//test !!!!!!!!!!!!!!!!!!!!!!!!!

 //Robot.W2_sp.full = 1000;//test !!!!!!!!!!!!!!!!!!!!!!!!!

 //Robot.W3_sp.full = 1000;//test !!!!!!!!!!!!!!!!!!!!!!!!!

 MAKsumA.full = Robot.W0_sp.byte[high] + Robot.W1_sp.byte[high] + Robot.W2_sp.byte[high] + Robot.W3_sp.byte[high] + Robot.SB_sp

 + Robot.W0_sp.byte[low ] + Robot.W1_sp.byte[low ] + Robot.W2_sp.byte[low ] + Robot.W3_sp.byte[low ] + Robot.orc_length ;

 MAKsumB.full = Robot.W0_sp.byte[high]*10 + Robot.W1_sp.byte[high]*9 + Robot.W2_sp.byte[high]*8 + Robot.W3_sp.byte[high]*7 + Robot.SB_sp*6

 + Robot.W0_sp.byte[low ]*5 + Robot.W1_sp.byte[low ]*4 + Robot.W2_sp.byte[low ]*3 + Robot.W3_sp.byte[low ]*2 + Robot.orc_length ;

 //in even cases micro puts data on F0 to F6 and clear data_clk pin (F7) to 0 ,so micro puts '0'+'data' on port F

 //so there is no need for "CLK_PORT.OUTCLR = CLK_PIN ;"

 send_packet[0] = 0b01010101 ; //first start sign

 send_packet[2] = 0b01010101 ; //second start sign

 send_packet[4] = ( ((Robot.W0_sp.byte[high] & 0x80) >> 7) |

 ((Robot.W1_sp.byte[high] & 0x80) >> 6) |

 ((Robot.W2_sp.byte[high] & 0x80) >> 5) |

 ((Robot.W3_sp.byte[high] & 0x80) >> 4) |

 ((Robot.SB_sp & 0x80) >> 3) |

 ((MAKsumA.byte[high] & 0x80) >> 2) |

 ((MAKsumB.byte[high] & 0x80) >> 1) ) & 0b01111111;

 send_packet[6] = ( ((Robot.W0_sp.byte[low] & 0x80) >> 7) |

 ((Robot.W1_sp.byte[low] & 0x80) >> 6) |

 ((Robot.W2_sp.byte[low] & 0x80) >> 5) |

 ((Robot.W3_sp.byte[low] & 0x80) >> 4) |

 ((Robot.orc_length & 0x80) >> 3) |

 ((MAKsumA.byte[low] & 0x80) >> 2) |

 ((MAKsumB.byte[low] & 0x80) >> 1) ) & 0b01111111;

 send_packet[8] = Robot.W0_sp.byte[high] & 0b01111111 ;

 send_packet[10] = Robot.W1_sp.byte[high] & 0b01111111 ;

 send_packet[12] = Robot.W2_sp.byte[high] & 0b01111111 ;

 send_packet[14] = Robot.W3_sp.byte[high] & 0b01111111 ;

 send_packet[16] = Robot.SB_sp & 0b01111111 ;

 send_packet[18] = MAKsumA.byte[high] & 0b01111111 ;

 send_packet[20] = MAKsumB.byte[high] & 0b01111111 ;

 send_packet[22] = Robot.W0_sp.byte[low] & 0b01111111 ;

 send_packet[24] = Robot.W1_sp.byte[low] & 0b01111111 ;

 send_packet[26] = Robot.W2_sp.byte[low] & 0b01111111 ;

 send_packet[28] = Robot.W3_sp.byte[low] & 0b01111111 ;

 send_packet[30] = Robot.orc_length & 0b01111111 ;

 send_packet[32] = MAKsumA.byte[low] & 0b01111111 ;

 send_packet[34] = MAKsumB.byte[low] & 0b01111111 ;

}

inline void fpga_connection ( void )

This function sends the packet created in inline void data_packing ( void ) and receives a packet from SPARTAN3 (FPGA). Sending in even cases and receicing in odd cases. PIN7 of PORTF ( FPGA_CLK ) is used for clock.

inline void fpga_connection ( void )

{

 if (packet_counter % 2 == 0)//sending

 {

 PORTF_OUT = send_packet[packet_counter] ;

 }

 else //receiving

 {

 ioport_set_value(FPGA_CLK, high);//CLK_PORT.OUTSET = CLK_PIN ;

 receive_packet[packet_counter] = PORTX_IN ;

 }

 if (packet_counter == 35)

 {

 number_of_sent_packet ++ ;

 data = unpacking_data ;

 }

}

inline void data_unpacking (void)

This function is the complementary of data_packing () . It generates checksum from received packet and tests whether the packet is correct or not.

inline void data_unpacking (void)

{

 //unpacking data from FPGA

 //High bytes

 temp_data[0].byte[high] = ( receive_packet[9] & 0b01111111 ) | ( ( receive_packet[5] & 0b00000001 ) << 7 ) ;

 temp_data[1].byte[high] = ( receive_packet[11] & 0b01111111 ) | ( ( receive_packet[5] & 0b00000010 ) << 6 ) ;

 temp_data[2].byte[high] = ( receive_packet[13] & 0b01111111 ) | ( ( receive_packet[5] & 0b00000100 ) << 5 ) ;

 temp_data[3].byte[high] = ( receive_packet[15] & 0b01111111 ) | ( ( receive_packet[5] & 0b00001000 ) << 4 ) ;

 temp_data[4].byte[high] = ( receive_packet[17] & 0b01111111 ) | ( ( receive_packet[5] & 0b00010000 ) << 3 ) ;

 temp_data[5].byte[high] = ( receive_packet[19] & 0b01111111 ) | ( ( receive_packet[5] & 0b00100000 ) << 2 ) ;

 temp_data[6].byte[high] = ( receive_packet[21] & 0b01111111 ) | ( ( receive_packet[5] & 0b01000000 ) << 1 ) ;

 /* temp_data[7] = ( receive_packet[21] & 0b01111111 ) ;*/

 //Low bytes

 temp_data[0].byte[low] = ( receive_packet[23] & 0b01111111 ) | ( ( receive_packet[7] & 0b00000001 ) << 7 ) ;

 temp_data[1].byte[low] = ( receive_packet[25] & 0b01111111 ) | ( ( receive_packet[7] & 0b00000010 ) << 6 ) ;

 temp_data[2].byte[low] = ( receive_packet[27] & 0b01111111 ) | ( ( receive_packet[7] & 0b00000100 ) << 5 ) ;

 temp_data[3].byte[low] = ( receive_packet[29] & 0b01111111 ) | ( ( receive_packet[7] & 0b00001000 ) << 4 ) ;

 temp_data[4].byte[low] = ( receive_packet[31] & 0b01111111 ) | ( ( receive_packet[7] & 0b00010000 ) << 3 ) ;

 temp_data[5].byte[low] = ( receive_packet[33] & 0b01111111 ) | ( ( receive_packet[7] & 0b00100000 ) << 2 ) ;

 temp_data[6].byte[low] = ( receive_packet[35] & 0b01111111 ) | ( ( receive_packet[7] & 0b01000000 ) << 1 ) ;

 /* temp_data[15] = ( receive_packet[39] & 0b01111111 ) ;*/

 //generating check_sum

 uint16_t MAKsumA ;

 uint16_t MAKsumB;

 MAKsumA = temp_data[0].byte[high] + temp_data[1].byte[high] + temp_data[2].byte[high] + temp_data[3].byte[high] + temp_data[4].byte[high] +

 temp_data[0].byte[low ] + temp_data[1].byte[low ] + temp_data[2].byte[low ] + temp_data[3].byte[low ] + temp_data[4].byte[low ] ;

 MAKsumB = temp_data[0].byte[high]*10 + temp_data[1].byte[high]*9 + temp_data[2].byte[high]*8 + temp_data[3].byte[high]*7 + temp_data[4].byte[high]*6 +

 temp_data[0].byte[low ]*5 + temp_data[1].byte[low ]*4 + temp_data[2].byte[low ]*3 + temp_data[3].byte[low ]*2 + temp_data[4].byte[low ] ;

 //saving checked data

 if( ( MAKsumA == temp_data[5].full ) && ( MAKsumB == temp_data[6].full))

 {

 Robot.W0.full = temp_data[0].full ;

 Robot.W1.full = temp_data[1].full ;

 Robot.W2.full = temp_data[2].full ;

 Robot.W3.full = temp_data[3].full ;

 Robot.SB.full = temp_data[4].full ;

 if(MAKsumA == 0 && MAKsumB == 0)

 {

 if (!(temp_data[0].full == 0 && temp_data[1].full == 0 && temp_data[2].full == 0 && temp_data[3].full == 0 && temp_data[4].full == 0))

 {

 number_of_received_packet ++ ;

 }

 }

 else

 {

 number_of_received_packet ++ ;

 }

 }

}

inline void free_wheel_function ( void )

It turns off all motors if :

  1. Battery voltage is low

  2. There is a over current alarm

  3. Wireless is disconnected

  4. Current sensors are not calibrated

  5. There is an order from wireless board to turn off motors

⚠️ Turning off is not the same as 0 % duty cycle for PWM

🔵 1-2-3-4-0-0-0-0 is a sign . FPGA recognizes it and turns off all motors

inline void free_wheel_function ( void )

{

 if (free_wheel.low_battery || free_wheel.motor_fault || free_wheel.wireless_timeout || !current_offset_check || (Robot.Vx_sp.full == 258 && Robot.Vy_sp.full == 772))

 {

 Robot.W0_sp.byte[high] = 1;

 Robot.W0_sp.byte[low ] = 2;

 Robot.W1_sp.byte[high] = 3;

 Robot.W1_sp.byte[low ] = 4;

 Robot.W2_sp.byte[high] = 0;

 Robot.W2_sp.byte[low ] = 0;

 Robot.W3_sp.byte[high] = 0;

 Robot.W3_sp.byte[low ] = 0;

 }

}

Timer_on(void) and Timer_show (void)

These two functions together works like a stopwatch.

//starting counter

inline void Timer_on(void)

{

 TCE0_CNT = 0 ;

 TCE1_CNT = 0 ;

}


inline void Timer_show (void)

{

 cycle_time_us = TCE1_CNT * 1e+3 + TCE0_CNT * 2 ;

 cycle_time_s = TCE1_CNT/1000.0 + TCE0_CNT/500000.0 ;

}
Clone this wiki locally