Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

buttons.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00051 #include <cfg/os.h>
00052 #include <cfg/clock.h>
00053 #include <arch/arm.h>
00054 #include <dev/irqreg.h>
00055 
00056 #include <sys/event.h>
00057 #include <sys/timer.h>
00058 
00059 #include "buttons.h"
00060 
00097 #if defined(AT91SAM7X_EK)
00098 #define BTN_TC_ID       TC1_ID
00099 #define BTN_PIO_ID      PIOB_ID
00100 #define BTN_DOWN_BIT    27
00101 //#define BTN_SELECT_BIT    28 //Doesn't work. Reason currently unknown.
00102 #define BTN_UP_BIT      29
00103 #elif defined(AT91SAM9260_EK)
00104 #define BTN_TC_ID       TC1_ID
00105 #define BTN_PIO_ID      PIOB_ID
00106 #define BTN_DOWN_BIT    8
00107 #define BTN_SELECT_BIT  9
00108 #define BTN_UP_BIT      10
00109 #endif
00110 
00111 #ifndef BTN_SCAN_FREQ
00112 
00115 #define BTN_SCAN_FREQ       128UL
00116 #endif
00117 
00118 #ifndef BTN_REPEAT_FIRST
00119 
00122 #define BTN_REPEAT_FIRST    100
00123 #endif
00124 
00125 #ifndef BTN_REPEAT_NEXT
00126 
00129 #define BTN_REPEAT_NEXT     25
00130 #endif
00131 
00153 #if BTN_PIO_ID == PIOB_ID
00154 #define BTN_PIO_PE_REG  PIOB_PER
00155 #define BTN_PIO_OD_REG  PIOB_ODR
00156 #define BTN_PIO_PDS_REG PIOB_PDSR
00157 #define BTN_PIO_PUE_REG PIOB_PUER
00158 #elif BTN_PIO_ID == PIOA_ID
00159 #define BTN_PIO_PE_REG  PIOA_PER
00160 #define BTN_PIO_OD_REG  PIOA_ODR
00161 #define BTN_PIO_PDS_REG PIOA_PDSR
00162 #define BTN_PIO_PUE_REG PIOA_PUER
00163 #elif BTN_PIO_ID == PIOC_ID
00164 #define BTN_PIO_PE_REG  PIOC_PER
00165 #define BTN_PIO_OD_REG  PIOC_ODR
00166 #define BTN_PIO_PDS_REG PIOC_PDSR
00167 #define BTN_PIO_PUE_REG PIOC_PUER
00168 #else
00169 #define BTN_PIO_PE_REG  PIO_PER
00170 #define BTN_PIO_OD_REG  PIO_ODR
00171 #define BTN_PIO_PDS_REG PIO_PDSR
00172 #define BTN_PIO_PUE_REG PIO_PUER
00173 #endif
00174 
00176 #ifdef BTN_SELECT_BIT
00177 #define BTN_SELECT      _BV(BTN_SELECT_BIT)
00178 #else
00179 #define BTN_SELECT      0
00180 #endif
00181 
00183 #ifdef BTN_UP_BIT
00184 #define BTN_UP          _BV(BTN_UP_BIT)
00185 #else
00186 #define BTN_UP          0
00187 #endif
00188 
00190 #ifdef BTN_DOWN_BIT
00191 #define BTN_DOWN        _BV(BTN_DOWN_BIT)
00192 #else
00193 #define BTN_DOWN        0
00194 #endif
00195 
00233 #if BTN_TC_ID == TC1_ID
00234 #define sig_BTN_TC      sig_TC1
00235 #define BTN_TC_CC_REG   TC1_CCR
00236 #define BTN_TC_CM_REG   TC1_CMR
00237 #define BTN_TC_IE_REG   TC1_IER
00238 #define BTN_TC_ID_REG   TC1_IDR
00239 #define BTN_TC_S_REG    TC1_SR
00240 #define BTN_TC_RC_REG   TC1_RC
00241 #elif BTN_TC_ID == TC2_ID
00242 #define sig_BTN_TC      sig_TC2
00243 #define BTN_TC_CC_REG   TC2_CCR
00244 #define BTN_TC_CM_REG   TC2_CMR
00245 #define BTN_TC_IE_REG   TC2_IER
00246 #define BTN_TC_ID_REG   TC2_IDR
00247 #define BTN_TC_S_REG    TC2_SR
00248 #define BTN_TC_RC_REG   TC2_RC
00249 #endif
00250 
00258 static HANDLE btn_que;
00259 
00266 static volatile u_int btn_pressed;
00267 
00271 static void ScanTimerInterrupt(void *arg)
00272 {
00273     static u_int btn_prev;
00274     static u_int btn_repeat;
00275     u_int btn_code;
00276 
00277     /* Read the negated GPIO line status. Pressing a button drives the pin low. */
00278     btn_code = ~inr(BTN_PIO_PDS_REG) & (BTN_DOWN | BTN_SELECT | BTN_UP);
00279     if (btn_code) {
00280         /* A button has been or still is pressed. */
00281         if (btn_code != btn_prev) {
00282             /* This is a new button. Immediately post an event. */
00283             btn_pressed = btn_code;
00284             NutEventPostFromIrq(&btn_que);
00285             /* Initialize the repeat rate. */
00286             btn_repeat = BTN_REPEAT_FIRST;
00287         }
00288         else if (btn_repeat == 0) {
00289             /* Button is still pressed and the repeat time elapsed. 
00290                Post a new event. */
00291             NutEventPostFromIrq(&btn_que);
00292             /* Re-initialize the repeat rate. */
00293             btn_repeat = BTN_REPEAT_NEXT;
00294         }
00295         else {
00296             /* Button is still pressed. Wait until repeat time elapses. */
00297             btn_repeat--;
00298         }
00299     }
00300     /* Keep the last code, so we are able to distinguish whether the user
00301        is still pressing the same or selected a new button. */
00302     btn_prev = btn_code;
00303 }
00304 
00314 void ButtonInit(void)
00315 {
00316     int dummy;
00317 
00318     /* Enable scan timer clock. */
00319     outr(PMC_PCER, _BV(BTN_TC_ID) | _BV(BTN_PIO_ID));
00320     /* Disable the Clock Counter */
00321     outr(BTN_TC_CC_REG, TC_CLKDIS);
00322     /* Disable all interrupts */
00323     outr(BTN_TC_ID_REG, 0xFFFFFFFF);
00324     /* Clear the status register. */
00325     dummy = inr(BTN_TC_S_REG);
00326     /* Select divider and compare trigger */
00327     outr(BTN_TC_CM_REG, TC_CLKS_MCK32 | TC_CPCTRG);
00328     /* Enable the Clock counter */
00329     outr(BTN_TC_CC_REG, TC_CLKEN);
00330     /* Validate the RC compare interrupt */
00331     outr(BTN_TC_IE_REG, TC_CPCS);
00332 
00333     /* Register timer interrupt handler. */
00334     NutRegisterIrqHandler(&sig_BTN_TC, ScanTimerInterrupt, 0);
00335     /* Set to lowest priority. */
00336     NutIrqSetPriority(&sig_BTN_TC, 0);
00337 
00338     /* Enable timer interrupts */
00339     NutIrqEnable(&sig_BTN_TC);
00340 
00341     /* Set compare value for specified scan frequency. */
00342 #if defined(AT91_PLL_MAINCK)
00343     outr(BTN_TC_RC_REG, At91GetMasterClock() / (32 * BTN_SCAN_FREQ));
00344 #else
00345     outr(BTN_TC_RC_REG, NutGetCpuClock() / (32 * BTN_SCAN_FREQ));
00346 #endif
00347 
00348     /* Initialize GPIO lines for buttons. */
00349     outr(BTN_PIO_PE_REG, BTN_SELECT | BTN_UP | BTN_DOWN);
00350     outr(BTN_PIO_OD_REG, BTN_SELECT | BTN_UP | BTN_DOWN);
00351     outr(BTN_PIO_PUE_REG, BTN_SELECT | BTN_UP | BTN_DOWN);
00352 
00353     /* Software trigger starts the scan timer. */
00354     outr(BTN_TC_CC_REG, TC_SWTRG);
00355 }
00356 
00370 char ButtonRead(u_long tmo)
00371 {
00372     /* Wait for a button event from the interrupt handler. */
00373     if (NutEventWait(&btn_que, tmo) == 0) {
00374         /* Copy the volatile value to a local variable. */
00375         u_int pressed = btn_pressed;
00376 
00377         if (pressed & BTN_SELECT) {
00378             return KEYCODE_SELECT;
00379         }
00380         if (pressed & BTN_DOWN) {
00381             return KEYCODE_DOWN;
00382         }
00383         if (pressed & BTN_UP) {
00384             return KEYCODE_UP;
00385         }
00386     }
00387     return 0;
00388 }

Generated on Fri Feb 23 17:28:49 2007 for SAM Internet Radio by  doxygen 1.4.4