| /*This file is prepared for Doxygen automatic documentation generation.*/ | |
| /*! \file ********************************************************************* | |
| * | |
| * \brief AT32UC3A EVK1100 board LEDs support package. | |
| * | |
| * This file contains definitions and services related to the LED features of | |
| * the EVK1100 board. | |
| * | |
| * - Compiler: IAR EWAVR32 and GNU GCC for AVR32 | |
| * - Supported devices: All AVR32 AT32UC3A devices can be used. | |
| * - AppNote: | |
| * | |
| * \author Atmel Corporation: http://www.atmel.com \n | |
| * Support and FAQ: http://support.atmel.no/ | |
| * | |
| ******************************************************************************/ | |
| /* Copyright (c) 2007, Atmel Corporation All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are met: | |
| * | |
| * 1. Redistributions of source code must retain the above copyright notice, | |
| * this list of conditions and the following disclaimer. | |
| * | |
| * 2. Redistributions in binary form must reproduce the above copyright notice, | |
| * this list of conditions and the following disclaimer in the documentation | |
| * and/or other materials provided with the distribution. | |
| * | |
| * 3. The name of ATMEL may not be used to endorse or promote products derived | |
| * from this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND | |
| * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, | |
| * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #include <avr32/io.h> | |
| #include "preprocessor.h" | |
| #include "compiler.h" | |
| #include "evk1100.h" | |
| #include "led.h" | |
| //! Structure describing LED hardware connections. | |
| typedef const struct | |
| { | |
| struct | |
| { | |
| U32 PORT; //!< LED GPIO port. | |
| U32 PIN_MASK; //!< Bit-mask of LED pin in GPIO port. | |
| } GPIO; //!< LED GPIO descriptor. | |
| struct | |
| { | |
| S32 CHANNEL; //!< LED PWM channel (< 0 if N/A). | |
| S32 FUNCTION; //!< LED pin PWM function (< 0 if N/A). | |
| } PWM; //!< LED PWM descriptor. | |
| } tLED_DESCRIPTOR; | |
| //! Hardware descriptors of all LEDs. | |
| static tLED_DESCRIPTOR LED_DESCRIPTOR[LED_COUNT] = | |
| { | |
| #define INSERT_LED_DESCRIPTOR(LED_NO, unused) \ | |
| { \ | |
| {LED##LED_NO##_GPIO / 32, 1 << (LED##LED_NO##_GPIO % 32)},\ | |
| {LED##LED_NO##_PWM, LED##LED_NO##_PWM_FUNCTION } \ | |
| }, | |
| MREPEAT(LED_COUNT, INSERT_LED_DESCRIPTOR, ~) | |
| #undef INSERT_LED_DESCRIPTOR | |
| }; | |
| //! Saved state of all LEDs. | |
| static volatile U32 LED_State = (1 << LED_COUNT) - 1; | |
| U32 LED_Read_Display(void) | |
| { | |
| return LED_State; | |
| } | |
| void LED_Display(U32 leds) | |
| { | |
| tLED_DESCRIPTOR *led_descriptor; | |
| volatile avr32_gpio_port_t *led_gpio_port; | |
| leds &= (1 << LED_COUNT) - 1; | |
| LED_State = leds; | |
| for (led_descriptor = &LED_DESCRIPTOR[0]; | |
| led_descriptor < LED_DESCRIPTOR + LED_COUNT; | |
| led_descriptor++) | |
| { | |
| led_gpio_port = &AVR32_GPIO.port[led_descriptor->GPIO.PORT]; | |
| if (leds & 1) | |
| { | |
| led_gpio_port->ovrc = led_descriptor->GPIO.PIN_MASK; | |
| } | |
| else | |
| { | |
| led_gpio_port->ovrs = led_descriptor->GPIO.PIN_MASK; | |
| } | |
| led_gpio_port->oders = led_descriptor->GPIO.PIN_MASK; | |
| led_gpio_port->gpers = led_descriptor->GPIO.PIN_MASK; | |
| leds >>= 1; | |
| } | |
| } | |
| U32 LED_Read_Display_Mask(U32 mask) | |
| { | |
| return Rd_bits(LED_State, mask); | |
| } | |
| void LED_Display_Mask(U32 mask, U32 leds) | |
| { | |
| tLED_DESCRIPTOR *led_descriptor = &LED_DESCRIPTOR[0] - 1; | |
| volatile avr32_gpio_port_t *led_gpio_port; | |
| U8 led_shift; | |
| mask &= (1 << LED_COUNT) - 1; | |
| Wr_bits(LED_State, mask, leds); | |
| while (mask) | |
| { | |
| led_shift = 1 + ctz(mask); | |
| led_descriptor += led_shift; | |
| led_gpio_port = &AVR32_GPIO.port[led_descriptor->GPIO.PORT]; | |
| leds >>= led_shift - 1; | |
| if (leds & 1) | |
| { | |
| led_gpio_port->ovrc = led_descriptor->GPIO.PIN_MASK; | |
| } | |
| else | |
| { | |
| led_gpio_port->ovrs = led_descriptor->GPIO.PIN_MASK; | |
| } | |
| led_gpio_port->oders = led_descriptor->GPIO.PIN_MASK; | |
| led_gpio_port->gpers = led_descriptor->GPIO.PIN_MASK; | |
| leds >>= 1; | |
| mask >>= led_shift; | |
| } | |
| } | |
| Bool LED_Test(U32 leds) | |
| { | |
| return Tst_bits(LED_State, leds); | |
| } | |
| void LED_Off(U32 leds) | |
| { | |
| tLED_DESCRIPTOR *led_descriptor = &LED_DESCRIPTOR[0] - 1; | |
| volatile avr32_gpio_port_t *led_gpio_port; | |
| U8 led_shift; | |
| leds &= (1 << LED_COUNT) - 1; | |
| Clr_bits(LED_State, leds); | |
| while (leds) | |
| { | |
| led_shift = 1 + ctz(leds); | |
| led_descriptor += led_shift; | |
| led_gpio_port = &AVR32_GPIO.port[led_descriptor->GPIO.PORT]; | |
| led_gpio_port->ovrs = led_descriptor->GPIO.PIN_MASK; | |
| led_gpio_port->oders = led_descriptor->GPIO.PIN_MASK; | |
| led_gpio_port->gpers = led_descriptor->GPIO.PIN_MASK; | |
| leds >>= led_shift; | |
| } | |
| } | |
| void LED_On(U32 leds) | |
| { | |
| tLED_DESCRIPTOR *led_descriptor = &LED_DESCRIPTOR[0] - 1; | |
| volatile avr32_gpio_port_t *led_gpio_port; | |
| U8 led_shift; | |
| leds &= (1 << LED_COUNT) - 1; | |
| Set_bits(LED_State, leds); | |
| while (leds) | |
| { | |
| led_shift = 1 + ctz(leds); | |
| led_descriptor += led_shift; | |
| led_gpio_port = &AVR32_GPIO.port[led_descriptor->GPIO.PORT]; | |
| led_gpio_port->ovrc = led_descriptor->GPIO.PIN_MASK; | |
| led_gpio_port->oders = led_descriptor->GPIO.PIN_MASK; | |
| led_gpio_port->gpers = led_descriptor->GPIO.PIN_MASK; | |
| leds >>= led_shift; | |
| } | |
| } | |
| void LED_Toggle(U32 leds) | |
| { | |
| tLED_DESCRIPTOR *led_descriptor = &LED_DESCRIPTOR[0] - 1; | |
| volatile avr32_gpio_port_t *led_gpio_port; | |
| U8 led_shift; | |
| leds &= (1 << LED_COUNT) - 1; | |
| Tgl_bits(LED_State, leds); | |
| while (leds) | |
| { | |
| led_shift = 1 + ctz(leds); | |
| led_descriptor += led_shift; | |
| led_gpio_port = &AVR32_GPIO.port[led_descriptor->GPIO.PORT]; | |
| led_gpio_port->ovrt = led_descriptor->GPIO.PIN_MASK; | |
| led_gpio_port->oders = led_descriptor->GPIO.PIN_MASK; | |
| led_gpio_port->gpers = led_descriptor->GPIO.PIN_MASK; | |
| leds >>= led_shift; | |
| } | |
| } | |
| U32 LED_Read_Display_Field(U32 field) | |
| { | |
| return Rd_bitfield(LED_State, field); | |
| } | |
| void LED_Display_Field(U32 field, U32 leds) | |
| { | |
| LED_Display_Mask(field, leds << ctz(field)); | |
| } | |
| U8 LED_Get_Intensity(U32 led) | |
| { | |
| tLED_DESCRIPTOR *led_descriptor; | |
| // Check that the argument value is valid. | |
| led = ctz(led); | |
| led_descriptor = &LED_DESCRIPTOR[led]; | |
| if (led >= LED_COUNT || led_descriptor->PWM.CHANNEL < 0) return 0; | |
| // Return the duty cycle value if the LED PWM channel is enabled, else 0. | |
| return (AVR32_PWM.sr & (1 << led_descriptor->PWM.CHANNEL)) ? | |
| AVR32_PWM.channel[led_descriptor->PWM.CHANNEL].cdty : 0; | |
| } | |
| void LED_Set_Intensity(U32 leds, U8 intensity) | |
| { | |
| tLED_DESCRIPTOR *led_descriptor = &LED_DESCRIPTOR[0] - 1; | |
| volatile avr32_pwm_channel_t *led_pwm_channel; | |
| volatile avr32_gpio_port_t *led_gpio_port; | |
| U8 led_shift; | |
| // For each specified LED... | |
| for (leds &= (1 << LED_COUNT) - 1; leds; leds >>= led_shift) | |
| { | |
| // Select the next specified LED and check that it has a PWM channel. | |
| led_shift = 1 + ctz(leds); | |
| led_descriptor += led_shift; | |
| if (led_descriptor->PWM.CHANNEL < 0) continue; | |
| // Initialize or update the LED PWM channel. | |
| led_pwm_channel = &AVR32_PWM.channel[led_descriptor->PWM.CHANNEL]; | |
| if (!(AVR32_PWM.sr & (1 << led_descriptor->PWM.CHANNEL))) | |
| { | |
| led_pwm_channel->cmr = (AVR32_PWM_CPRE_MCK << AVR32_PWM_CPRE_OFFSET) & | |
| ~(AVR32_PWM_CALG_MASK | | |
| AVR32_PWM_CPOL_MASK | | |
| AVR32_PWM_CPD_MASK); | |
| led_pwm_channel->cprd = 0x000000FF; | |
| led_pwm_channel->cdty = intensity; | |
| AVR32_PWM.ena = 1 << led_descriptor->PWM.CHANNEL; | |
| } | |
| else | |
| { | |
| AVR32_PWM.isr; | |
| while (!(AVR32_PWM.isr & (1 << led_descriptor->PWM.CHANNEL))); | |
| led_pwm_channel->cupd = intensity; | |
| } | |
| // Switch the LED pin to its PWM function. | |
| led_gpio_port = &AVR32_GPIO.port[led_descriptor->GPIO.PORT]; | |
| if (led_descriptor->PWM.FUNCTION & 0x1) | |
| { | |
| led_gpio_port->pmr0s = led_descriptor->GPIO.PIN_MASK; | |
| } | |
| else | |
| { | |
| led_gpio_port->pmr0c = led_descriptor->GPIO.PIN_MASK; | |
| } | |
| if (led_descriptor->PWM.FUNCTION & 0x2) | |
| { | |
| led_gpio_port->pmr1s = led_descriptor->GPIO.PIN_MASK; | |
| } | |
| else | |
| { | |
| led_gpio_port->pmr1c = led_descriptor->GPIO.PIN_MASK; | |
| } | |
| led_gpio_port->gperc = led_descriptor->GPIO.PIN_MASK; | |
| } | |
| } |