Source

pymite / src / platform / stm32f4 / gpio.py

Full commit
# This file is Copyright 2012 JMSI
#
## @file
#  @copybrief gpio
#
## @package gpio
#  @brief STM32 GPIO Access Module
#
# Provides generic access to the stm32 GPIOs

"""__NATIVE__
#include "plat.h"
#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"

#define HIGH Bit_SET
#define LOW Bit_RESET

#define _digitalWrite(GPIOx, GPIO_Pin, BitVal) { \
    GPIO_WriteBit(GPIOx, GPIO_Pin, BitVal); \
}

/*
 * Loads the correct STM32 GPIOs from the first
 * Python argument, and integer pin number (0-15) from second argument.
 * Port name argument is expected to be a single-character string with the port
 * letter ([a-dA-D])
 *
 * port_reg argument is optional.
 */
PmReturn_t  _get_port_register(GPIO_TypeDef **port_reg,
                               uint16_t *pin_mask,
                               uint8_t *pin_num)
{
    pPmObj_t pa;
    pPmObj_t pb;
    PmReturn_t retval = PM_RET_OK;

    pa = NATIVE_GET_LOCAL(0);
    if (OBJ_GET_TYPE(pa) != OBJ_TYPE_STR)
    {
      PM_RAISE(retval, PM_RET_EX_TYPE);
      return retval;
    }

    pb = NATIVE_GET_LOCAL(1);
    if (OBJ_GET_TYPE(pb) != OBJ_TYPE_INT)
    {
      PM_RAISE(retval, PM_RET_EX_TYPE);
      return retval;
    }

    // Only single-character strings for the port number
    if ((((pPmString_t)pa)->length) != 1)
    {
      PM_RAISE(retval, PM_RET_EX_VAL);
      return retval;
    }

    // Find port & direction regs (TODO: Possibly make a PROGMEM lookup table)
    switch(((pPmString_t)pa)->val[0])
    {
      case 'a':
      case 'A':
        if(port_reg) *port_reg = GPIOA;
        break;
      case 'b':
      case 'B':
        if(port_reg) *port_reg = GPIOB;
        break;
      case 'c':
      case 'C':
        if(port_reg) *port_reg = GPIOC;
        break;
      case 'd':
      case 'D':
        if(port_reg) *port_reg = GPIOD;
        break;
      case 'e':
      case 'E':
        if(port_reg) *port_reg = GPIOE;
        break;
      case 'f':
      case 'F':
        if(port_reg) *port_reg = GPIOF;
        break;
      default:
        PM_RAISE(retval, PM_RET_EX_VAL);
        return retval;
    }

    // Check pin is in range
    if(((pPmInt_t)pb)->val < 0 || ((pPmInt_t)pb)->val > 15)
    {
        PM_RAISE(retval, PM_RET_EX_VAL);
        return retval;
    }
    *pin_mask = 1<<((pPmInt_t)pb)->val;
    *pin_num = ((pPmInt_t)pb)->val;

    return retval;
}


PmReturn_t change_port_state(uint8_t state){

    pPmObj_t pa;
    PmReturn_t retval = PM_RET_OK;
    
    if(NATIVE_GET_NUM_ARGS() != 1)
    {
      PM_RAISE(retval, PM_RET_EX_TYPE);
      return retval;
    }
    
    pa = NATIVE_GET_LOCAL(0);
    if (OBJ_GET_TYPE(pa) != OBJ_TYPE_STR)
    {
      PM_RAISE(retval, PM_RET_EX_TYPE);
      return retval;
    }
    
    // Find port & direction regs (TODO: Possibly make a PROGMEM lookup table)
    switch(((pPmString_t)pa)->val[0])
    {
      case 'a':
      case 'A':
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, state);
        break;
      case 'b':
      case 'B':
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, state);
        break;
      case 'c':
      case 'C':
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, state);
        break;
      case 'd':
      case 'D':
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, state);
        break;
      case 'e':
      case 'E':
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, state);
        break;
      case 'f':
      case 'F':
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, state);
        break;
      case 'g':
      case 'G':
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, state);
        break;
      case 'h':
      case 'H':
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH, state);
        break;
      case 'i':
      case 'I':
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOI, state);
        break;
      default:
        PM_RAISE(retval, PM_RET_EX_VAL);
        return retval;
    }
    return retval;
}
"""

INPUT = 0
OUTPUT = 0x01
HIGH = True
LOW = False
    
def enable_port(port):
    """___NATIVE__

    return change_port_state(ENABLE);
    """
    pass
    
def disable_port(port):
    """___NATIVE__
    return change_port_state(DISABLE);
    """
    pass
    
# Reads a single pin of a particular STM32 port
#
# Port is specified as a single-character string, A-F.
# Pin is specified as an integer, 0-15
#
# Return value is boolean True/False, can be treated as 1/0
def _digitalRead(port, pin):
    """__NATIVE__
    GPIO_TypeDef *port;
    uint16_t pin_mask;
    uint8_t pin_num;
    
    PmReturn_t retval = PM_RET_OK;
    /*
    if(NATIVE_GET_NUM_ARGS() != 2)
    {
      PM_RAISE(retval, PM_RET_EX_TYPE);
      return retval;
    }

    retval = _get_port_register(&port, &pin_mask, &pin_num);
    if(retval != PM_RET_OK)
      return retval;
    
    pPmObj_t pa = ((port->IDR & pin_mask) != (uint32_t)Bit_RESET) ? PM_TRUE : PM_FALSE;
    NATIVE_SET_TOS(pa); // Push our result object onto the stack*/
    return retval;
    """
    pass

def digitalRead(pin):
    """
    digital read from static pin name
    see pin.py module
    """
    _digitalRead(pin[0],pin[1])
    

def _get_pin_mask(pin_num):
    return 1<<pin_num
    
def configure_pin(port, pin_num):
    pass

# Writes a single pin of a particular STM32 port
#
# Port is specified as a single-character string, A-F.
# Pin is specified as an integer, 0-15
# Value is either boolean True/False or Integer 0 or non-zero.
#
def _digital_write(port, pin, value):
    """__NATIVE__
    GPIO_TypeDef *port;
    uint16_t pin_mask;
    uint8_t pin_num;
    pPmObj_t pc;
    PmReturn_t retval = PM_RET_OK;

    NATIVE_SET_TOS(PM_NONE);

    if(NATIVE_GET_NUM_ARGS() != 3)
    {
      PM_RAISE(retval, PM_RET_EX_TYPE);
      return retval;
    }

    retval = _get_port_register(&port, &pin_mask, &pin_num);
    if(retval != PM_RET_OK)
      return retval;

    pc = NATIVE_GET_LOCAL(2);

    /* If the arg is not an integer, raise TypeError */
    if (OBJ_GET_TYPE(pc) != OBJ_TYPE_INT && OBJ_GET_TYPE(pc) != OBJ_TYPE_BOOL)
    {
      PM_RAISE(retval, PM_RET_EX_TYPE);
      return retval;
    }

    if(((pPmInt_t)pc)->val) {
      //GPIO_SetBits(port, pin_mask);
      port->BSRRL = pin_mask;
    } else {
      //GPIO_ResetBits(port, pin_mask);
      port->BSRRH = pin_mask;
    }
    
    return retval;
    """
    pass
    
def digital_write(pin, value):
    """
    digital write on pin from static pin name
    see pin.py module
    """
    _digital_write(pin[0], pin[1], value)

def _pin_mode(port, pin, direction):
    """__NATIVE__
    GPIO_TypeDef *port;
    uint16_t pin_mask;
    uint8_t pin_num;
    pPmObj_t pc;
    PmReturn_t retval = PM_RET_OK;

    NATIVE_SET_TOS(PM_NONE);

    if(NATIVE_GET_NUM_ARGS() != 3)
    {
      PM_RAISE(retval, PM_RET_EX_TYPE);
      return retval;
    }

    retval = _get_port_register(&port, &pin_mask, &pin_num);
    if(retval != PM_RET_OK)
      return retval;

    pc = NATIVE_GET_LOCAL(2);

    /* If the arg is not an integer, raise TypeError */
    if (OBJ_GET_TYPE(pc) != OBJ_TYPE_INT && OBJ_GET_TYPE(pc) != OBJ_TYPE_BOOL)
    {
      PM_RAISE(retval, PM_RET_EX_TYPE);
      return retval;
    }
    
    port->MODER  &= ~(GPIO_MODER_MODER0 << (pin_num * 2));
    port->MODER  |= (((pPmInt_t)pc)->val << (pin_num * 2));
    
    /* Speed mode configuration */
    port->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 << (pin_num * 2));
    port->OSPEEDR |= ((uint32_t)(GPIO_Speed_100MHz) << (pin_num * 2));
    
    return retval;	
	"""
    pass

def pin_mode(pin, direction):
    """
    configure pin mode from static pin name
    see pin.py module
    """
    _pin_mode(pin[0],pin[1],direction)