Subversion Repositories HomeAutomation

Rev

Rev 682 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /**
  2.  * AntennaControl
  3.  *
  4.  * Build for use at ETA, http://www.eta.chalmers.se/
  5.  * controlling their 2 meter yagi antenna.
  6.  * For the moment only support for azimuth,
  7.  * elevation is yet to be implemented.
  8.  *
  9.  * @date 2007-12-10
  10.  * @author Erik Larsson
  11.  *
  12.  */
  13.  
  14. /*
  15.  * This version uses a NodeEssential
  16.  * and the pins used are:
  17.  * 0: PD2 azimuth plus
  18.  * 1: PD1 azimuth minus
  19.  * 8: PC4 ADC4 azimuth feedback
  20.  */
  21.  
  22. /*-----------------------------------------------------------------------------
  23.  * Includes
  24.  *---------------------------------------------------------------------------*/
  25. #include <inttypes.h>
  26. #include <avr/interrupt.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <avr/eeprom.h>
  30. #include <config.h> // All configuration parameters
  31. #include <bios.h>   // BIOS interface declarations, including CAN structure and ID defines.
  32. #include <drivers/timer/timer.h>
  33.  
  34. /*-----------------------------------------------------------------------------
  35.  * Defines
  36.  *---------------------------------------------------------------------------*/
  37. #define APP_TYPE    0xf0a0
  38. #define APP_VERSION 0x0002
  39.  
  40. #define AZIMUTH 0
  41.  
  42. #define ROTATE_STOP 0
  43. #define ROTATE_PLUS 1
  44. #define ROTATE_MINUS 2
  45.  
  46. #define SET 0
  47. #define GET 1
  48.  
  49. #define CALIBRATE_AZIMUTH 0 // EEPROM adress
  50.  
  51. // Make sure this is a power of 2
  52. #define AVERAGE_SIZE 16
  53. #define AVERAGE_SIZE_SHIFT 4
  54.  
  55. //FIXME move these message id defines
  56. #define MSG_CAL_SET 0x11100001UL
  57. #define MSG_CAL_GET 0x11100002UL
  58. #define MSG_ABS 0x111000031UL
  59. #define MSG_REL 0x11100004UL
  60. #define MSG_START 0x11100005UL
  61. #define MSG_STOP 0x11100006UL
  62. #define MSG_STATUS 0x11100007UL
  63. #define MSG_CAL_RET 0x111000f2UL
  64.  
  65.  
  66. // A simple message "queue", with space for one message only.
  67. // These are declared volatile to tell the compiler not to optimize away accesses.
  68. volatile Can_Message_t rxMsg; // Message storage
  69. volatile uint8_t rxMsgFull;   // Synchronization flag
  70.  
  71. // For calculating average feedback measurement
  72. uint16_t azimuthReadout[ AVERAGE_SIZE ];
  73.  
  74. uint16_t azimuthCalibration;
  75.  
  76. /*-----------------------------------------------------------------------------
  77.  * Declarations
  78.  *---------------------------------------------------------------------------*/
  79.  
  80. /**
  81.  * calibration
  82.  * Sets and gets calibration data from EEPROM
  83.  *
  84.  * @param mode: set /get
  85.  * @param value
  86.  * @return value
  87.  */
  88. int16_t calibration( uint8_t mode, uint16_t value );
  89.  
  90. // Turn rotor
  91. // position: 0-1024
  92. /**
  93.  * turn
  94.  * Turns rotor to given position
  95.  * FIXME implement this function
  96.  *
  97.  * @param position
  98.  * @return
  99.  */
  100. uint8_t turn( uint16_t position );
  101.  
  102. /**
  103.  * getPosition
  104.  * Calculates the antenna position
  105.  * Uses a number of the latest adc readings
  106.  * and gets the avarage value
  107.  *
  108.  * @param void
  109.  * @return position
  110.  */
  111. uint16_t getPosition( void );
  112.  
  113. /**
  114.  * initAdcFeedback
  115.  * Starts the ADC
  116.  *
  117.  * @param void
  118.  * @return void
  119.  */
  120. void initAdcFeedback( void );
  121.  
  122. /**
  123.  * readFeedback
  124.  * Gets antenna position from ADC and
  125.  * puts in arrary for later calculations
  126.  *
  127.  * @param void
  128.  * @return void
  129.  */
  130. void readFeedback( void );
  131.  
  132. /**
  133.  * controlRelay
  134.  * Control the relay that turns the rotor
  135.  *
  136.  * @param direction
  137.  * @return void
  138.  */
  139. void controlRelay( uint8_t direction );
  140.  
  141. /**
  142.  * sendStatus
  143.  * Sends antennas position on CAN bus
  144.  *
  145.  * @param void
  146.  * @return void
  147.  */
  148. void sendStatus( void );
  149.  
  150. // CAN message reception callback.
  151. // This function runs with interrupts disabled, keep it as short as possible.
  152. void can_receive( Can_Message_t *msg ) {
  153.     if (!rxMsgFull) {
  154.         memcpy((void*)&rxMsg, msg, sizeof(rxMsg));
  155.         rxMsgFull = 1;
  156.     }
  157. }
  158.  
  159. /*-----------------------------------------------------------------------------
  160.  * Main Program
  161.  *---------------------------------------------------------------------------*/
  162. int main( void )
  163. {
  164.     // Enable interrupts as early as possible
  165.     sei();
  166.    
  167.     Timer_Init();
  168.  
  169.     DDRD |= (1 << PD1)|(1 << PD2);
  170.     PORTD |= (1 << PD1)|(1 << PD2);
  171.  
  172.     // Setup ADC
  173.     initAdcFeedback();
  174.    
  175.     Can_Message_t txMsg;
  176.     txMsg.Id = (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE) | (NODE_ID << CAN_SHIFT_NMT_SID);
  177.     txMsg.DataLength = 4;
  178.     txMsg.RemoteFlag = 0;
  179.     txMsg.ExtendedFlag = 1;
  180.     txMsg.Data.words[0] = APP_TYPE;
  181.     txMsg.Data.words[1] = APP_VERSION;
  182.    
  183.     // Set up callback for CAN reception, this is optional if only sending is required.
  184.     BIOS_CanCallback = &can_receive;
  185.     // Send CAN_NMT_APP_START
  186.     BIOS_CanSend(&txMsg);
  187.    
  188.     // Read calibration value from eeprom
  189.     azimuthCalibration = eeprom_read_word( CALIBRATE_AZIMUTH );
  190.    
  191.     // Timer for reading position feedback
  192.     Timer_SetTimeout(0, 50, TimerTypeFreeRunning, 0);
  193.     Timer_SetTimeout(1, 1000, TimerTypeFreeRunning, 0);
  194.  
  195.     sendStatus();
  196.  
  197.     while (1) {
  198.         if (Timer_Expired(0)) {
  199.             // Periodicly read antennas position
  200.             readFeedback();
  201.         }
  202.         if (Timer_Expired(1)) {
  203.             // Send antennas position
  204.             sendStatus();
  205.         }
  206.        
  207.         /* If any messages is received */
  208.         if (rxMsgFull) {
  209.  
  210.             switch ( rxMsg.Id ){
  211.                 case MSG_CAL_SET:
  212.                     // Set calibration value
  213.                     if( 2 == rxMsg.DataLength ){
  214.  
  215.                         calibration( SET, rxMsg.Data.words[0] );
  216.                     }
  217.                    
  218.                     break;
  219.                    
  220.                 case MSG_CAL_GET:
  221.                     // Get calibration value
  222.                     if( 0 == rxMsg.DataLength ){
  223.  
  224.                         txMsg.Id = MSG_CAL_RET;
  225.                         txMsg.DataLength = 2;
  226.                         txMsg.Data.words[0] = calibration( GET, 0 );
  227.  
  228.                         BIOS_CanSend(&txMsg);
  229.                     }
  230.                    
  231.                     break;
  232.                    
  233.                 case MSG_ABS:
  234.                     // Start turning to absolute position
  235.                     if( 2 == rxMsg.DataLength ){
  236.  
  237.                         //FIXME implement this
  238.                     }
  239.                    
  240.                     break;
  241.                    
  242.                 case MSG_REL:
  243.                     // Start turning to relative position
  244.                     if( 2 == rxMsg.DataLength ){
  245.  
  246.                         //FIXME implement this
  247.                     }
  248.                    
  249.                     break;
  250.                    
  251.                 case MSG_START:
  252.                     // Start turning rotor
  253.                     if( 1 == rxMsg.DataLength ){
  254.  
  255.                         // First data byte decides direction
  256.                         controlRelay( rxMsg.Data.bytes[0] );
  257.                     }
  258.                    
  259.                     break;
  260.                    
  261.                 case MSG_STOP:
  262.                     // Stop turning rotor
  263.                    
  264.                     controlRelay( ROTATE_STOP );
  265.                    
  266.                     break;
  267.                    
  268.                 case MSG_STATUS:
  269.                     // Get position
  270.                     if( 0 == rxMsg.DataLength ){
  271.                         sendStatus();
  272.                     }
  273.                    
  274.                     break;
  275.                    
  276.                 default:
  277.                     break;
  278.             }
  279.  
  280.             rxMsgFull = 0;
  281.         }
  282.     }
  283.    
  284.     return 0;
  285. }
  286.  
  287. /*-----------------------------------------------------------------------------
  288.  * Definitions
  289.  *---------------------------------------------------------------------------*/
  290.  
  291. int16_t calibration( uint8_t mode, uint16_t value )
  292. {
  293.     // set / get calibration value
  294.     if( SET == mode ){
  295.         eeprom_write_word( CALIBRATE_AZIMUTH, value );
  296.         azimuthCalibration = value;
  297.    
  298.     }else if( GET == mode ){
  299.         return azimuthCalibration;
  300.     }
  301.     return 0;
  302. }
  303.  
  304. uint8_t turn( uint16_t position )
  305. {
  306.     //FIXME implement this
  307.     // start relay
  308.     // read feedback
  309.     // callibrate measurement
  310.    
  311.     while(0){
  312.        
  313.     }
  314.     return 0;
  315. }
  316.  
  317. uint16_t getPosition( void )
  318. {
  319.     uint16_t position = 0;
  320.    
  321.     // Get average value of position
  322.     for( uint8_t i=0; i < AVERAGE_SIZE; i++ ){
  323.         position += azimuthReadout[i];
  324.     }
  325.    
  326.     // Calculate average
  327.     position = position >> AVERAGE_SIZE_SHIFT;
  328.  
  329.     // Convert to degrees, gives about 379 degrees
  330.     position /= 3;
  331.  
  332.     // Calibrate
  333.     position += (int16_t)azimuthCalibration;
  334.    
  335.     return position;
  336. }
  337.  
  338. void initAdcFeedback( void )
  339. {
  340.     // ADC4: Azimuth feedback
  341.    
  342.     // Enable ADC4
  343.     ADMUX |= ( 1 << MUX2 );
  344.     ADMUX &= ~(( 1 << MUX0 )|( 1 << MUX1 )|( 1 << MUX3 ));
  345.  
  346.     // Prescaler /128
  347.     ADCSRA |= ( 1 << ADPS2)|( 1 << ADPS1)|( 1 << ADPS0);
  348.    
  349.     // Enable AVcc as Voltage Reference
  350.     ADMUX |= ( 1 << REFS0 );
  351.     ADMUX &= ~( 1 << REFS1 );
  352.    
  353.     // Right adjust the result
  354.     ADMUX &= ~( 1 << ADLAR );
  355.    
  356.     // Disable digital input
  357.     DIDR0 |= ( 1 << ADC5D )|( 1 << ADC4D );
  358.    
  359.     // Wake up ADC and enable it
  360.     PRR &= ~( 1 << PRADC );
  361.     ADCSRA |= ( 1 << ADEN );
  362.    
  363.     // Start first conversion
  364.     ADCSRA |= ( 1 << ADSC );
  365. }
  366.  
  367. void controlRelay( uint8_t direction )
  368. {
  369.     if( ROTATE_PLUS == direction ){
  370.         // Turn CW
  371.         PORTD &= ~(1 << PD2);
  372.         PORTD |= (1 << PD1);
  373.     }else if ( ROTATE_MINUS == direction ){
  374.         // Turn CCW
  375.         PORTD &= ~(1 << PD1);
  376.         PORTD |= (1 << PD2);
  377.     }else{
  378.         // Stop azimuth rotor
  379.         PORTD |= (1 << PD1);
  380.         PORTD |= (1 << PD2);
  381.     }
  382. }
  383.  
  384. void readFeedback( void )
  385. {
  386.     static uint8_t azimuthArrayPosition = 0;
  387.  
  388.     // Wait for ADC conversion to complete
  389.     while( ADCSRA & ( 1 << ADSC )){}
  390.    
  391.     // Put readout in ringbuffer
  392.     azimuthReadout[ azimuthArrayPosition ] = ADCW;
  393.     azimuthArrayPosition++;
  394.    
  395.     if( AVERAGE_SIZE <= azimuthArrayPosition ){
  396.         azimuthArrayPosition = 0;
  397.     }
  398.    
  399.     // Start next conversion
  400.     ADCSRA |= ( 1 << ADSC );
  401. }
  402.  
  403. void sendStatus( void )
  404. {
  405.     // Gets antennas position and sends on CAN bus
  406.     Can_Message_t txMsg;
  407.    
  408.     txMsg.Id = 0x1f8f0100UL; //FIXME id should not be defined here
  409.    
  410.     txMsg.DataLength = 2;
  411.     txMsg.RemoteFlag = 0;
  412.     txMsg.ExtendedFlag = 1;
  413.    
  414.     txMsg.Data.words[ 0 ] = getPosition();
  415.    
  416.     BIOS_CanSend( &txMsg );
  417.    
  418. }
  419.  
  420.