avr.py

Go to the documentation of this file.
00001 # This file is Copyright 2007, 2009, 2010 Dean Hall.
00002 #
00003 # This file is part of the Python-on-a-Chip program.
00004 # Python-on-a-Chip is free software: you can redistribute it and/or modify
00005 # it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1.
00006 #
00007 # Python-on-a-Chip is distributed in the hope that it will be useful,
00008 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00009 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00010 # A copy of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1
00011 # is seen in the file COPYING in this directory.
00012 
00013 ## @file
00014 #  @copybrief avr
00015 
00016 ## @package avr
00017 #  @brief AVR Access Module
00018 #
00019 # Provides generic access to the AVR microcontroller
00020 #
00021 # Note that to save RAM when the module is imported, many of the
00022 # port & ddr methods below are commented out. Uncomment and recompile
00023 # in order to use!
00024 #
00025 # <b>USAGE</b>
00026 #
00027 # \code
00028 # import avr
00029 # avr.ddrA(0) # Set all pins as input
00030 # a = avr.portA()
00031 # avr.ddrA(0xFF) # Set all pins as output
00032 # avr.portA(42)
00033 #
00034 # avr.delay(500) # Half second pause
00035 #
00036 # if avr.digitalRead('A', 3):
00037 #   avr.digitalWrite('D', 0, True)
00038 # \endcode
00039 
00040 
00041 """__NATIVE__
00042 #include <avr/io.h>
00043 #include <util/delay.h>
00044 
00045 /*
00046  * Common method for all port register operations
00047  */
00048 PmReturn_t
00049 _portX(volatile uint8_t *port,
00050        volatile uint8_t *direction,
00051        volatile uint8_t *pin)
00052 {
00053    pPmObj_t pa;
00054    PmReturn_t retval = PM_RET_OK;
00055 
00056    switch (NATIVE_GET_NUM_ARGS())
00057    {
00058       /* If no argument is present, return PIN reg value */
00059       case 0:
00060 
00061         /* Read port and create a Python integer from its value */
00062         retval = int_new(*pin, &pa);
00063 
00064         /* Return the integer on the stack */
00065         NATIVE_SET_TOS(pa);
00066         break;
00067 
00068       /* If one argument is present, set port to that value */
00069       case 1:
00070          pa = NATIVE_GET_LOCAL(0);
00071          /* If the arg is not an integer, raise TypeError */
00072          if (OBJ_GET_TYPE(pa) != OBJ_TYPE_INT)
00073          {
00074            PM_RAISE(retval, PM_RET_EX_TYPE);
00075            break;
00076          }
00077 
00078          NATIVE_SET_TOS(PM_NONE);
00079 
00080          /* Set PORT to the low byte of the integer value */
00081          *port = ((pPmInt_t)pa)->val;
00082          break;
00083 
00084       /* If an invalid number of args are present, raise TypeError */
00085       default:
00086          PM_RAISE(retval, PM_RET_EX_TYPE);
00087          break;
00088     }
00089 
00090     return retval;
00091 }
00092 
00093 
00094 /*
00095  * Set a DDR register to the first Python argument
00096  */
00097 PmReturn_t _ddrX(volatile uint8_t *direction)
00098 {
00099    PmReturn_t retval = PM_RET_OK;
00100    pPmObj_t pa;
00101    if(NATIVE_GET_NUM_ARGS() != 1)
00102    {
00103       PM_RAISE(retval, PM_RET_EX_TYPE);
00104       return retval;
00105    }
00106 
00107    pa = NATIVE_GET_LOCAL(0);
00108    if (OBJ_GET_TYPE(pa) != OBJ_TYPE_INT)
00109    {
00110       PM_RAISE(retval, PM_RET_EX_TYPE);
00111       return retval;
00112    }
00113 
00114    *direction = (uint8_t) ((pPmInt_t)pa)->val;
00115    NATIVE_SET_TOS(PM_NONE);
00116    return retval;
00117 }
00118 
00119 
00120 
00121 /*
00122  * Loads the correct AVR port registers & direction address from the first
00123  * Python argument, and integer pin number (0-7) from second argument.
00124  * Port name argument is expected to be a single-character string with the port
00125  * letter ([a-dA-D])
00126  *
00127  * Both port_reg & port_reg arguments are optional.
00128  *
00129  * TODO: Look into putting this into a table in PROGMEM instead of a switch
00130  * statement
00131  */
00132 PmReturn_t  _get_port_register(volatile uint8_t **pin_reg,
00133                                volatile uint8_t **port_reg,
00134                                volatile uint8_t **direction,
00135                                uint8_t *pin)
00136 {
00137     pPmObj_t pa;
00138     pPmObj_t pb;
00139     PmReturn_t retval = PM_RET_OK;
00140 
00141     pa = NATIVE_GET_LOCAL(0);
00142     if (OBJ_GET_TYPE(pa) != OBJ_TYPE_STR)
00143     {
00144       PM_RAISE(retval, PM_RET_EX_TYPE);
00145       return retval;
00146     }
00147 
00148     pb = NATIVE_GET_LOCAL(1);
00149     if (OBJ_GET_TYPE(pb) != OBJ_TYPE_INT)
00150     {
00151       PM_RAISE(retval, PM_RET_EX_TYPE);
00152       return retval;
00153     }
00154 
00155     // Only single-character strings for the port number
00156     if ((((pPmString_t)pa)->length) != 1)
00157     {
00158       PM_RAISE(retval, PM_RET_EX_VAL);
00159       return retval;
00160     }
00161 
00162     // Find port & direction regs (TODO: Possibly make a PROGMEM lookup table)
00163     switch(((pPmString_t)pa)->val[0])
00164     {
00165       case 'a':
00166       case 'A':
00167         if(port_reg) *port_reg = &PORTA;
00168         if(pin_reg) *pin_reg = &PINA;
00169         *direction = &DDRA;
00170         break;
00171       case 'b':
00172       case 'B':
00173         if(port_reg) *port_reg = &PORTB;
00174         if(pin_reg) *pin_reg = &PINB;
00175         *direction = &DDRB;
00176         break;
00177       case 'c':
00178       case 'C':
00179 #if defined(PORTC) && defined(PINC) && defined(DDRC)
00180         if(port_reg) *port_reg = &PORTC;
00181         if(pin_reg) *pin_reg = &PINC;
00182         *direction = &DDRC;
00183 #endif
00184         break;
00185       case 'd':
00186       case 'D':
00187 #if defined(PORTD) && defined(PIND) && defined(DDRD)
00188         if(port_reg) *port_reg = &PORTD;
00189         if(pin_reg) *pin_reg = &PIND;
00190         *direction = &DDRD;
00191 #endif
00192         break;
00193       case 'e':
00194       case 'E':
00195 #if defined(PORTE) && defined(PINE) && defined(DDRE)
00196         if(port_reg) *port_reg = &PORTE;
00197         if(pin_reg) *pin_reg = &PINE;
00198         *direction = &DDRE;
00199 #endif
00200         break;
00201       case 'f':
00202       case 'F':
00203 #if defined(PORTF) && defined(PINF) && defined(DDRF)
00204         if(port_reg) *port_reg = &PORTF;
00205         if(pin_reg) *pin_reg = &PINF;
00206         *direction = &DDRF;
00207 #endif
00208         break;
00209       default:
00210         PM_RAISE(retval, PM_RET_EX_VAL);
00211         return retval;
00212     }
00213 
00214     // Check pin is in range
00215     if(((pPmInt_t)pb)->val < 0 || ((pPmInt_t)pb)->val > 7)
00216     {
00217         PM_RAISE(retval, PM_RET_EX_VAL);
00218         return retval;
00219     }
00220     *pin = ((pPmInt_t)pb)->val;
00221 
00222     return retval;
00223 }
00224 
00225 """
00226 
00227 
00228 # Port methods are commented out by default because of the amount of RAM
00229 # used when the module is loaded. Uncomment the ones you need...
00230 
00231 def portA(a):
00232     """__NATIVE__
00233     return _portX(&PORTA, &DDRA, &PINA);
00234     """
00235     pass
00236 
00237 # def portB(a):
00238 #     """__NATIVE__
00239 #     return _portX(&PORTB, &DDRB, &PINB);
00240 #     """
00241 #     pass
00242 
00243 # def portC(a):
00244 #     """__NATIVE__
00245 #     return _portX(&PORTC, &DDRC, &PINC);
00246 #     """
00247 #     pass
00248 
00249 # def portD(a):
00250 #     """__NATIVE__
00251 #     return _portX(&PORTD, &DDRD, &PIND);
00252 #     """
00253 #     pass
00254 
00255 # def portE(a):
00256 #     """__NATIVE__
00257 #     return _portX(&PORTE, &DDRE, &PINE);
00258 #     """
00259 #     pass
00260 
00261 # def portF(a):
00262 #     """__NATIVE__
00263 #     return _portX(&PORTF, &DDRF, &PINF);
00264 #     """
00265 #     pass
00266 
00267 def ddrA(a):
00268     """__NATIVE__
00269     return _ddrX(&DDRA);
00270     """
00271     pass
00272 
00273 # def ddrB(a):
00274 #     """__NATIVE__
00275 #     return _ddrX(&DDRB);
00276 #     """
00277 #     pass
00278 
00279 # def ddrC(a):
00280 #     """__NATIVE__
00281 #     return _ddrX(&DDRC);
00282 #     """
00283 #     pass
00284 
00285 
00286 # def ddrD(a):
00287 #     """__NATIVE__
00288 #     return _ddrX(&DDRD);
00289 #     """
00290 #     pass
00291 
00292 # def ddrE(a):
00293 #     """__NATIVE__
00294 #     return _ddrX(&DDRE);
00295 #     """
00296 #     pass
00297 
00298 # def ddrF(a):
00299 #     """__NATIVE__
00300 #     return _ddrX(&DDRF);
00301 #     """
00302 #     pass
00303 
00304 
00305 # Reads a single pin of a particular AVR port
00306 #
00307 # Port is specified as a single-character string, A-F.
00308 # Pin is specified as an integer, 0-7
00309 #
00310 # Return value is boolean True/False, can be treated as 1/0
00311 def digitalRead(port, pin):
00312     """__NATIVE__
00313     volatile uint8_t *port;
00314     volatile uint8_t *direction;
00315     uint8_t pin;
00316     PmReturn_t retval = PM_RET_OK;
00317 
00318     if(NATIVE_GET_NUM_ARGS() != 2)
00319     {
00320       PM_RAISE(retval, PM_RET_EX_TYPE);
00321       return retval;
00322     }
00323 
00324     retval = _get_port_register(&port, NULL, &direction, &pin);
00325     if(retval != PM_RET_OK)
00326       return retval;
00327 
00328     *direction &= ~(1<<pin); // Set pin to input
00329     pPmObj_t pa = (*port & (1<<pin)) ? PM_TRUE : PM_FALSE;
00330     NATIVE_SET_TOS(pa); // Push our result object onto the stack
00331     return retval;
00332     """
00333     pass
00334 
00335 
00336 # Writes a single pin of a particular AVR port
00337 #
00338 # Port is specified as a single-character string, A-F.
00339 # Pin is specified as an integer, 0-7
00340 # Value is either boolean True/False or Integer 0 or non-zero.
00341 #
00342 def digitalWrite(port, pin, value):
00343     """__NATIVE__
00344     volatile uint8_t *port;
00345     volatile uint8_t *direction;
00346     uint8_t pin;
00347     pPmObj_t pc;
00348     PmReturn_t retval = PM_RET_OK;
00349 
00350     NATIVE_SET_TOS(PM_NONE);
00351 
00352     if(NATIVE_GET_NUM_ARGS() != 3)
00353     {
00354       PM_RAISE(retval, PM_RET_EX_TYPE);
00355       return retval;
00356     }
00357 
00358     retval = _get_port_register(NULL, &port, &direction, &pin);
00359     if(retval != PM_RET_OK)
00360       return retval;
00361 
00362     pc = NATIVE_GET_LOCAL(2);
00363 
00364     /* If the arg is not an integer, raise TypeError */
00365     if (OBJ_GET_TYPE(pc) != OBJ_TYPE_INT && OBJ_GET_TYPE(pc) != OBJ_TYPE_BOOL)
00366     {
00367       PM_RAISE(retval, PM_RET_EX_TYPE);
00368       return retval;
00369     }
00370 
00371     *direction |= (1<<pin); // Set pin to output
00372 
00373     if(((pPmInt_t)pc)->val)
00374       *port |= 1<<pin;
00375     else
00376       *port &= ~(1<<pin);
00377     return retval;
00378     """
00379     pass
00380 
00381 
00382 def delay(ms):
00383     """__NATIVE__
00384     PmReturn_t retval = PM_RET_OK;
00385 
00386     if(NATIVE_GET_NUM_ARGS() != 1)
00387     {
00388       PM_RAISE(retval, PM_RET_EX_TYPE);
00389       return retval;
00390     }
00391 
00392     pPmObj_t pa = NATIVE_GET_LOCAL(0);
00393     if (OBJ_GET_TYPE(pa) == OBJ_TYPE_INT)
00394     {
00395       _delay_ms((double) ((pPmInt_t)pa)->val);
00396     }
00397     else if (OBJ_GET_TYPE(pa) == OBJ_TYPE_FLT)
00398     {
00399       _delay_ms((double) ((pPmFloat_t)pa)->val);
00400     }
00401     else
00402     {
00403       PM_RAISE(retval, PM_RET_EX_TYPE);
00404     }
00405 
00406     NATIVE_SET_TOS(PM_NONE);
00407     return retval;
00408     """
00409     pass
00410 
00411 
00412 
00413 # :mode=c:

Generated on Mon Oct 18 07:40:46 2010 for Python-on-a-chip by  doxygen 1.5.9