Subversion Repositories HomeAutomation

Rev

Rev 1516 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /**
  2.  * PCA95xx device driver. Provides possibility for several independent users of the
  3.  * device.
  4.  *
  5.  * @author  Anders Runeson
  6.  *
  7.  * @date    2010-04-02
  8.  */
  9.  
  10. /*-----------------------------------------------------------------------------
  11.  * Includes
  12.  *---------------------------------------------------------------------------*/
  13. #include <inttypes.h>
  14. #include <avr/io.h>
  15. #include <avr/interrupt.h>
  16.  
  17. #include <drivers/io/PCA95xx.h>
  18.  
  19. #if USE_PCA95XX==1
  20.  
  21. /*-----------------------------------------------------------------------------
  22.  * Globals
  23.  *---------------------------------------------------------------------------*/
  24. volatile uint8_t Pca95xx_address;
  25. volatile uint16_t Pca95xx_direction;
  26. volatile uint16_t Pca95xx_outputs;
  27.  
  28. #if PCA95XX_USE_INTERRUPT == 1
  29. volatile pca95xxCallback_t Pca95xx_callback[PCA95XX_NUM_CALLBACKS];
  30. #endif
  31.  
  32.  
  33. /*-----------------------------------------------------------------------------
  34.  * Interrupt Service Routines
  35.  *---------------------------------------------------------------------------*/
  36. #if PCA95XX_USE_INTERRUPT == 1
  37. ISR(PCA_INT_VECTOR)
  38. {
  39.     uint8_t t;
  40.     PCA_INT_DISABLE();
  41.     sei();
  42.     /* Read input registers from device */
  43.     uint16_t inputs = Pca95xx_GetInputs();
  44.    
  45.     /* Call all callbacks with the input as argument */
  46.     for (t = 0; t < PCA95XX_NUM_CALLBACKS; t++)
  47.     {
  48.         Pca95xx_callback[t](inputs);
  49.     }
  50.     PCA_INT_ENABLE();
  51. }
  52. #endif
  53.  
  54. /*-----------------------------------------------------------------------------
  55.  * Public Functions
  56.  *---------------------------------------------------------------------------*/
  57.  
  58. void Pca95xx_Init(uint8_t address)
  59. {
  60.     unsigned char messageBuf[5];
  61.    
  62.     /* Store address */
  63.     Pca95xx_address = (PCA95xx_I2C_DEV_ADDR|(address&7));
  64.  
  65. #if PCA95XX_DEBUG==1
  66.     printf("a0x%04X\n", Pca95xx_address);
  67. #endif
  68.  
  69.     /* Set up interrupt */
  70. #if PCA95XX_USE_INTERRUPT == 1
  71. #if PCA_INT_VECTOR==INT0_vect
  72.     DDRD &=~(1<<PD2);
  73.     PORTD|=(1<<PD2);    /* setup pullup on interrupt input */
  74. #else
  75.     DDRD &=~(1<<PD3);
  76.     PORTD|=(1<<PD3);    /* setup pullup on interrupt input */
  77. #endif
  78. #endif
  79.     /* Set up ports? */
  80.     TWI_Master_Initialise();
  81.  
  82.     /* Read output registers from device to global var */
  83.     messageBuf[0] = (Pca95xx_address<<TWI_ADR_BITS) | (FALSE<<TWI_READ_BIT);
  84.     messageBuf[1] = PCA95xx_REG_OUTPUT0;
  85.     TWI_Start_Read_Write( messageBuf, 2 );
  86.     while ( TWI_Transceiver_Busy() );
  87.     messageBuf[0] = (Pca95xx_address<<TWI_ADR_BITS) | (TRUE<<TWI_READ_BIT);
  88.     TWI_Start_Read_Write( messageBuf, 3 );
  89.     while ( TWI_Transceiver_Busy() );
  90.     if (TWI_Read_Data_From_Buffer(messageBuf, 3) == TRUE)
  91.     {
  92.         /* Disable interrupts while tampering with the global vars */
  93.         uint8_t sreg = SREG;
  94.         cli();
  95.         Pca95xx_outputs = (messageBuf[2]<<8)|messageBuf[1];
  96.         SREG = sreg;
  97. #if PCA95XX_DEBUG==1
  98.         printf("o0x%04X\n", Pca95xx_outputs);
  99. #endif
  100.     }
  101.  
  102.     /* Read direction registers from device to global var */
  103.     messageBuf[0] = (Pca95xx_address<<TWI_ADR_BITS) | (FALSE<<TWI_READ_BIT);
  104.     messageBuf[1] = PCA95xx_REG_CONF0;
  105.     TWI_Start_Read_Write( messageBuf, 2 );
  106.     while ( TWI_Transceiver_Busy() );
  107.     messageBuf[0] = (Pca95xx_address<<TWI_ADR_BITS) | (TRUE<<TWI_READ_BIT);
  108.     TWI_Start_Read_Write( messageBuf, 3 );
  109.     while ( TWI_Transceiver_Busy() );
  110.     if (TWI_Read_Data_From_Buffer(messageBuf, 3) == TRUE)
  111.     {
  112.         /* Disable interrupts while tampering with the global vars */
  113.         uint8_t sreg = SREG;
  114.         cli();
  115.         Pca95xx_direction = (messageBuf[2]<<8)|messageBuf[1];
  116.         SREG = sreg;
  117. #if PCA95XX_DEBUG==1
  118.         printf("d0x%04X\n", Pca95xx_direction);
  119. #endif
  120.     }
  121.  
  122.     /* Enable interrupt */
  123. #if PCA95XX_USE_INTERRUPT == 1
  124.     PCA_INT_ENABLE();
  125. #endif
  126. }
  127.  
  128. /*---------------------------------------------------------------------------*/
  129.  
  130. #if PCA95XX_USE_INTERRUPT == 1
  131. void Pca95xx_SetCallback(uint8_t index, pca95xxCallback_t callback)
  132. {
  133.     /* Disable interrupts while tampering with the global vars */
  134.     uint8_t sreg = SREG;
  135.     cli();
  136.  
  137.     if (index < PCA95XX_NUM_CALLBACKS)
  138.     {
  139.         /* Store the callback */
  140.         Pca95xx_callback[index] = callback;
  141.     }
  142.  
  143.     SREG = sreg;
  144. }
  145. #endif
  146.  
  147. /*---------------------------------------------------------------------------*/
  148.  
  149. uint16_t Pca95xx_GetInputs(void)
  150. {
  151.     unsigned char messageBuf[5];
  152.  
  153.     /* Disable device interrupts while communicating with the device */
  154.     //TODO: Interupts needed for I2C...
  155.     uint16_t inputs = 0;
  156.  
  157.     /* Read input registers from device */
  158.     messageBuf[0] = (Pca95xx_address<<TWI_ADR_BITS) | (FALSE<<TWI_READ_BIT);
  159.     messageBuf[1] = PCA95xx_REG_INPUT0;
  160.     TWI_Start_Read_Write( messageBuf, 2 );
  161.     while ( TWI_Transceiver_Busy() );
  162.     messageBuf[0] = (Pca95xx_address<<TWI_ADR_BITS) | (TRUE<<TWI_READ_BIT);
  163.     TWI_Start_Read_Write( messageBuf, 3 );
  164.     while ( TWI_Transceiver_Busy() );
  165.     if (TWI_Read_Data_From_Buffer(messageBuf, 3) == TRUE)
  166.     {
  167.         inputs = (messageBuf[2]<<8)|messageBuf[1];
  168. #if PCA95XX_DEBUG==1
  169.         printf("i0x%04X\n", inputs);
  170. #endif
  171.     }
  172.    
  173.     return inputs;
  174. }
  175.  
  176. /*---------------------------------------------------------------------------*/
  177.  
  178. void Pca95xx_SetOutputs(uint16_t outputs, uint16_t mask)
  179. {
  180.     unsigned char messageBuf[5];
  181. #if PCA95XX_DEBUG==1
  182.     printf("o0x%04X\n", Pca95xx_outputs);
  183. #endif
  184.  
  185.     /* Disable interrupts while tampering with the global vars */
  186.     uint8_t sreg = SREG;
  187.     cli();
  188.     /* Set masked ones in outputs to global var */
  189.     Pca95xx_outputs |= (outputs&mask);
  190.     /* Clear masked zeros in outputs to global var */
  191.     Pca95xx_outputs &= (outputs|(~mask));
  192.     /* Set output registers */
  193.     messageBuf[0] = (Pca95xx_address<<TWI_ADR_BITS) | (FALSE<<TWI_READ_BIT);
  194.     messageBuf[1] = PCA95xx_REG_OUTPUT0;
  195.     messageBuf[2] = Pca95xx_outputs&0xff;
  196.     messageBuf[3] = (Pca95xx_outputs>>8)&0xff;
  197.     SREG = sreg;
  198.     TWI_Start_Read_Write( messageBuf, 4 );
  199.     while ( TWI_Transceiver_Busy() );
  200.  
  201. #if PCA95XX_DEBUG==1
  202.     printf("o0x%04X\n", Pca95xx_outputs);
  203. #endif
  204. }
  205.  
  206. /*---------------------------------------------------------------------------*/
  207.  
  208. void Pca95xx_SetDirection(uint16_t direction, uint16_t mask)
  209. {
  210.     unsigned char messageBuf[5];
  211. #if PCA95XX_DEBUG==1
  212.     printf("d0x%04X\n", Pca95xx_direction);
  213. #endif
  214.  
  215.     /* Disable interrupts while tampering with the global vars */
  216.     uint8_t sreg = SREG;
  217.     cli();
  218.     /* Set masked ones in direction to global var */
  219.     Pca95xx_direction |= (direction&mask);
  220.     /* Clear masked zeros in direction to global var */
  221.     Pca95xx_direction &= (direction|(~mask));
  222.     /* Set direction registers */
  223.     messageBuf[0] = (Pca95xx_address<<TWI_ADR_BITS) | (FALSE<<TWI_READ_BIT);
  224.     messageBuf[1] = PCA95xx_REG_CONF0;
  225.     messageBuf[2] = Pca95xx_direction&0xff;
  226.     messageBuf[3] = (Pca95xx_direction>>8)&0xff;
  227.     SREG = sreg;
  228.     TWI_Start_Read_Write( messageBuf, 4 );
  229.     while ( TWI_Transceiver_Busy() );
  230.  
  231. #if PCA95XX_DEBUG==1
  232.     printf("d0x%04X\n", Pca95xx_direction);
  233. #endif
  234. }
  235.  
  236.  
  237.  
  238. /* GPIO.H interface */
  239.  
  240. /* Port output functions */
  241. void Pca95xx_set_pin(uint8_t nr)
  242. {
  243.     Pca95xx_SetOutputs(1<<nr, 1<<nr);
  244. }
  245.  
  246. void Pca95xx_clr_pin(uint8_t nr)
  247. {
  248.     Pca95xx_SetOutputs(0<<nr, 1<<nr);
  249. }
  250.  
  251. void Pca95xx_set_statement(uint8_t statement, uint8_t nr)
  252. {
  253.     Pca95xx_SetOutputs((statement)<<nr, 1<<nr);
  254. }
  255.  
  256. void Pca95xx_toggle_pin(uint8_t nr)
  257. {
  258.     Pca95xx_SetOutputs(Pca95xx_outputs^(1<<nr), 1<<nr);
  259. }
  260.  
  261. uint8_t Pca95xx_get_output_state(uint8_t nr)
  262. {
  263.     return ((Pca95xx_outputs>>nr)&0x1);
  264. }
  265.  
  266.  
  267. /* Port input functions */
  268. uint8_t Pca95xx_get_state(uint8_t nr)
  269. {
  270.     return ((Pca95xx_GetInputs()>>nr)&0x1);
  271. }
  272.  
  273.  
  274. /* Direction functions */
  275. void Pca95xx_set_in(uint8_t nr)
  276. {
  277.     Pca95xx_SetDirection(PCA95xx_CONF_INPUT<<nr, 1<<nr);
  278. }
  279.  
  280. void Pca95xx_set_out(uint8_t nr)
  281. {
  282.     Pca95xx_SetDirection(PCA95xx_CONF_OUTPUT<<nr, 1<<nr);
  283. }
  284.  
  285. uint8_t Pca95xx_get_direction(uint8_t nr)
  286. {
  287.     return ((Pca95xx_direction>>nr)&0x1);
  288. }
  289.  
  290. #endif
  291.