//------------------------------------------------------------------- // Filename: hal_digio.c // Description: HAL digital IO functionality //------------------------------------------------------------------- //------------------------------------------------------------------- // INCLUDES //------------------------------------------------------------------- #include "hal_defs.h" #include "hal_int.h" #include "hal_digio.h" //------------------------------------------------------------------- // LOCAL VARIABLES //------------------------------------------------------------------- static ISR_FUNC_PTR port0_isr_tbl[8] = { 0 }; static ISR_FUNC_PTR port1_isr_tbl[8] = { 0 }; static ISR_FUNC_PTR port2_isr_tbl[5] = { 0 }; // Find a better place for this! #define PICTL_PADSC_BM 0x80 #define PICTL_P2IEN_BM 0x40 #define PICTL_P0IENH_BM 0x20 #define PICTL_P0IENL_BM 0x10 #define PICTL_P2ICON_BM 0x08 #define PICTL_P1ICONH_BM 0x04 #define PICTL_P1ICONL_BM 0x02 #define PICTL_P1ICON_BM 0x06 // Combined - for compatibility #define PICTL_P0ICON_BM 0x01 //------------------------------------------------------------------- // GLOBAL FUNCTIONS //------------------------------------------------------------------- //------------------------------------------------------------------- // @fn halDigioConfig // @brief Configure the pin as specified by p. // @param digioConfig* p - pointer to configuration structure for IO pin // @return uint8 - HAL_DIGIO_ERROR or HAL_DIGIO_OK //------------------------------------------------------------------- //comment: find better way of doing this. SFR registers can not be accessed by pointers, therefore code is different from MSP430 code // comment: currently support only P0 and P1 uint8 halDigioConfig(const digioConfig *p) { // register volatile uint8* dir; register const uint8 bitmask = p->pin_bm; // Sanity check if ((bitmask == 0) || (bitmask != (uint8)BV(p->pin))) { return (HAL_DIGIO_ERROR); } switch (p->port) { case 0: P0SEL &= ~bitmask; if (p->dir == HAL_DIGIO_OUTPUT) { if (p->initval == 1) { P0 |= bitmask; } else { P0 &= ~bitmask; } P0DIR |= bitmask; } else // input { P0DIR &= ~bitmask; } break; case 1: P1SEL &= ~bitmask; if (p->dir == HAL_DIGIO_OUTPUT) { if (p->initval == 1) { P1 |= bitmask; } else { P1 &= ~bitmask; } P1DIR |= bitmask; } else // input { P1DIR &= ~bitmask; } break; case 2: P2SEL &= ~bitmask; if (p->dir == HAL_DIGIO_OUTPUT) { if (p->initval == 1) { P2 |= bitmask; } else { P2 &= ~bitmask; } P2DIR |= bitmask; } else // input { P2DIR &= ~bitmask; } break; //case 1: P1SEL &= ~bitmask; out = &P1OUT; dir = &P1DIR; break; //case 2: P2SEL &= ~bitmask; out = &P2OUT; dir = &P2DIR; break; default: return (HAL_DIGIO_ERROR); } return (HAL_DIGIO_OK); } //------------------------------------------------------------------- // @fn halDigioSet // @brief Set output pin // @param digioConfig* p - pointer to configuration structure for IO pin // @return uint8 - HAL_DIGIO_ERROR or HAL_DIGIO_OK //------------------------------------------------------------------- uint8 halDigioSet(const digioConfig *p) { if (p->dir == HAL_DIGIO_OUTPUT) { switch (p->port) { case 0: P0 |= p->pin_bm; break; case 1: P1 |= p->pin_bm; break; case 2: P2 |= p->pin_bm; break; default: return (HAL_DIGIO_ERROR); } return (HAL_DIGIO_OK); } return (HAL_DIGIO_ERROR); } //------------------------------------------------------------------- // @fn halDigioClear // @brief Clear output pin // @param digioConfig* p - pointer to configuration structure for IO pin // @return uint8 - HAL_DIGIO_ERROR or HAL_DIGIO_OK //------------------------------------------------------------------- uint8 halDigioClear(const digioConfig *p) { if (p->dir == HAL_DIGIO_OUTPUT) { switch (p->port) { case 0: P0 &= ~p->pin_bm; break; case 1: P1 &= ~p->pin_bm; break; case 2: P2 &= ~p->pin_bm; break; default: return (HAL_DIGIO_ERROR); } return (HAL_DIGIO_OK); } return (HAL_DIGIO_ERROR); } //------------------------------------------------------------------- // @fn halDigioToggle // @brief Toggle output pin // @param digioConfig* p - pointer to configuration structure for IO pin // @return uint8 - HAL_DIGIO_ERROR or HAL_DIGIO_OK //------------------------------------------------------------------- uint8 halDigioToggle(const digioConfig *p) { if (p->dir == HAL_DIGIO_OUTPUT) { switch (p->port) { case 0: P0 ^= p->pin_bm; break; case 1: P1 ^= p->pin_bm; break; case 2: P2 ^= p->pin_bm; break; default: return (HAL_DIGIO_ERROR); } return (HAL_DIGIO_OK); } return (HAL_DIGIO_ERROR); } //------------------------------------------------------------------- // @fn halDigioGet // @brief Get value on input pin // @param digioConfig* p - pointer to configuration structure for IO pin // @return uint8 - HAL_DIGIO_ERROR or HAL_DIGIO_OK //------------------------------------------------------------------- uint8 halDigioGet(const digioConfig *p) { if (p->dir == HAL_DIGIO_INPUT) { switch (p->port) { case 0: return (P0 &p->pin_bm ? 1 : 0); case 1: return (P1 &p->pin_bm ? 1 : 0); case 2: return (P2 &p->pin_bm ? 1 : 0); default: break; } } return (HAL_DIGIO_ERROR); } //------------------------------------------------------------------- // @fn halDigioIntConnect // @brief Connect function to IO interrupt // @param digioConfig* p - pointer to configuration structure for IO pin // ISR_FUNC_PTR func - pointer to function // @return uint8 - HAL_DIGIO_ERROR or HAL_DIGIO_OK //------------------------------------------------------------------- uint8 halDigioIntConnect(const digioConfig *p, ISR_FUNC_PTR func) { istate_t key; HAL_INT_LOCK(key); switch (p->port) { case 0: port0_isr_tbl[p->pin] = func; break; case 1: port1_isr_tbl[p->pin] = func; break; case 2: port2_isr_tbl[p->pin] = func; break; default: HAL_INT_UNLOCK(key); return (HAL_DIGIO_ERROR); } halDigioIntClear(p); HAL_INT_UNLOCK(key); return (HAL_DIGIO_OK); } //------------------------------------------------------------------- // @fn halDigioIntEnable // @brief Enable interrupt on IO pin // @param digioConfig* p - pointer to configuration structure for IO pin // @return uint8 - HAL_DIGIO_ERROR or HAL_DIGIO_OK //------------------------------------------------------------------- uint8 halDigioIntEnable(const digioConfig *p) { switch (p->port) { case 0: P0IE = 1; // set P0IE bit P0IEN |= p->pin_bm; break; case 1: IEN2 |= 0x10; // set P1IE bit P1IEN |= p->pin_bm; break; case 2: IEN2 |= 0x02; // set P2IE bit P2IEN |= p->pin_bm; break; default: return (HAL_DIGIO_ERROR); } return (HAL_DIGIO_OK); } //------------------------------------------------------------------- // @fn halDigioIntDisable // @brief Disable interrupt on IO pin // @param digioConfig* p - pointer to configuration structure for IO pin // @return uint8 - HAL_DIGIO_ERROR or HAL_DIGIO_OK //------------------------------------------------------------------- uint8 halDigioIntDisable(const digioConfig *p) { switch (p->port) { case 0: P0IEN &= ~p->pin_bm; break; case 1: P1IEN &= ~p->pin_bm; break; case 2: P2IEN &= ~p->pin_bm; break; default: return (HAL_DIGIO_ERROR); } return (HAL_DIGIO_OK); } //------------------------------------------------------------------- // @fn halDigioIntClear // @brief Clear interrupt flag // @param digioConfig* p - pointer to configuration structure for IO pin // @return uint8 - HAL_DIGIO_ERROR or HAL_DIGIO_OK //------------------------------------------------------------------- uint8 halDigioIntClear(const digioConfig *p) { switch (p->port) { case 0: P0IFG &= ~p->pin_bm; break; case 1: P1IFG &= ~p->pin_bm; break; case 2: P2IFG &= ~p->pin_bm; break; default: return (HAL_DIGIO_ERROR); } return (HAL_DIGIO_OK); } //------------------------------------------------------------------- // @fn halDigioIntSetEdge // @brief Set edge for IO interrupt // @param digioConfig* p - pointer to configuration structure for IO pin // edge - HAL_DIGIO_INT_FALLING_EDGE or HAL_DIGIO_INT_RISING_EDGE // @return uint8 - HAL_DIGIO_ERROR or HAL_DIGIO_OK //------------------------------------------------------------------- // Comment: all pins on port are configured at same time uint8 halDigioIntSetEdge(const digioConfig *p, uint8 edge) { switch (edge) { case HAL_DIGIO_INT_FALLING_EDGE: switch (p->port) { case 0: PICTL |= PICTL_P0ICON_BM; // set P0ICON high break; case 1: PICTL |= PICTL_P1ICON_BM; // set P1ICON high break; case 2: PICTL |= PICTL_P2ICON_BM; // set P2ICON high break; default: return (HAL_DIGIO_ERROR); } break; case HAL_DIGIO_INT_RISING_EDGE: switch (p->port) { case 0: PICTL &= ~PICTL_P0ICON_BM; // set P0ICON low break; case 1: PICTL &= ~PICTL_P1ICON_BM; // set P0ICON low break; case 2: PICTL &= ~PICTL_P2ICON_BM; // set P0ICON low break; default: return (HAL_DIGIO_ERROR); } break; default: return (HAL_DIGIO_ERROR); } return (HAL_DIGIO_OK); } //------------------------------------------------------------------- // @fn port0_ISR // @brief ISR framework for P0 digio interrupt // @param none // @return none //------------------------------------------------------------------- HAL_ISR_FUNCTION(port0_ISR, P0INT_VECTOR) { register uint8 i; P0IF = 0; if (P0IFG) { for (i = 0; i < 8; i++) { register const uint8 pinmask = 1 << i; if (P0IFG &pinmask) { if (port0_isr_tbl[i] != 0) { (*port0_isr_tbl[i])(); } P0IFG &= ~pinmask; } } //__low_power_mode_off_on_exit(); } } //------------------------------------------------------------------- // @fn port1_ISR // @brief ISR framework for P0 digio interrupt // @param none // @return none //------------------------------------------------------------------- HAL_ISR_FUNCTION(port1_ISR, P1INT_VECTOR) { register uint8 i; P1IF = 0; if (P1IFG) { for (i = 0; i < 8; i++) { register const uint8 pinmask = 1 << i; if (P1IFG &pinmask) { if (port1_isr_tbl[i] != 0) { (*port1_isr_tbl[i])(); } P1IFG &= ~pinmask; } } //__low_power_mode_off_on_exit(); } } //------------------------------------------------------------------- // @fn port2_ISR // @brief ISR framework for P2 digio interrupt // @param none // @return none //------------------------------------------------------------------- HAL_ISR_FUNCTION(port2_ISR, P2INT_VECTOR) { register uint8 i; P2IF = 0; if (P2IFG) { for (i = 0; i < 5; i++) { register const uint8 pinmask = 1 << i; if (P2IFG &pinmask) { if (port2_isr_tbl[i] != 0) { (*port2_isr_tbl[i])(); } P2IFG &= ~pinmask; } } //__low_power_mode_off_on_exit(); } }