ref: c60c0cbb4919e1bef859ba53580f42189fa0e455
dir: /demos/stm32f429_disco/stm/stm32f429/stm32f429i_discovery_ioe.c/
/**
******************************************************************************
* @file stm32f429i_discovery_ioe.c
* @author MCD Application Team
* @version V1.0.1
* @date 28-October-2013
* @brief This file provides a set of functions needed to manage the STMPE811
* IO Expander device mounted on STM32F429I-DISCO Kit.
******************************************************************************
* @attention
*
* <h2><center>© COPYRIGHT 2013 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* File Info : ---------------------------------------------------------------
Note:
-----
- This driver uses the DMA method for sending and receiving data on I2C bus
which allow higher efficiency and reliability of the communication.
SUPPORTED FEATURES:
- Touch Panel Features: Single point mode (Polling/Interrupt)
----------------------------------------------------------------------------*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f429i_discovery_ioe.h"
/** @addtogroup Utilities
* @{
*/
/** @addtogroup STM32F4_DISCOVERY
* @{
*/
/** @addtogroup STM32F429I_DISCOVERY
* @{
*/
/** @defgroup STM32F429I_DISCOVERY_IOE
* @brief This file includes the IO Expander driver for STMPE811 IO Expander
* devices.
* @{
*/
/** @defgroup STM32F429I_DISCOVERY_IOE_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup STM32F429I_DISCOVERY_IOE_Private_Defines
* @{
*/
#define TIMEOUT_MAX 0x3000 /*<! The value of the maximal timeout for I2C waiting loops */
/**
* @}
*/
/** @defgroup STM32F429I_DISCOVERY_IOE_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup STM32F429I_DISCOVERY_IOE_Private_Variables
* @{
*/
TP_STATE TP_State; /* The global structure holding the TS state */
uint32_t IOE_TimeOut = TIMEOUT_MAX; /* Value of Timeout when I2C communication fails */
/**
* @}
*/
/** @defgroup STM32F429I_DISCOVERY_IOE_Private_FunctionPrototypes
* @{
*/
static uint16_t IOE_TP_Read_X(void);
static uint16_t IOE_TP_Read_Y(void);
static uint16_t IOE_TP_Read_Z(void);
static void IOE_GPIO_Config(void);
static void IOE_I2C_Config(void);
static void IOE_DMA_Config(IOE_DMADirection_TypeDef Direction, uint8_t* buffer);
#ifndef USE_Delay
static void delay(__IO uint32_t nCount);
#endif /* USE_Delay */
/**
* @}
*/
/** @defgroup STM32F429I_DISCOVERY_IOE_Private_Functions
* @{
*/
/**
* @brief Initializes and Configures the IO_Expander Touch Panel Functionality
* and configures all STM32F429I_DISCO necessary
* hardware (GPIOs, APB clocks ..).
* @param None
* @retval IOE_OK if all initializations done correctly. Other value if error.
*/
uint8_t IOE_Config(void)
{
/* Configure the needed pins */
IOE_GPIO_Config();
/* I2C initialization */
IOE_I2C_Config();
/* Read IO Expander ID */
if(IOE_IsOperational())
{
return IOE_NOT_OPERATIONAL;
}
/* Generate IO Expander Software reset */
IOE_Reset();
/* IO Expander configuration */
/* Touch Panel controller and ADC configuration */
IOE_FnctCmd(IOE_ADC_FCT, ENABLE);
IOE_TP_Config();
/* Configuration is OK */
return IOE_OK;
}
/**
* @brief Enables the touch Panel interrupt.
* @param None
* @retval IOE_OK: if all initializations are OK. Other value if error.
*/
uint8_t IOE_TPITConfig(void)
{
/* Enable the Global interrupt */
IOE_GITCmd(ENABLE);
/* Enable the Global GPIO Interrupt */
IOE_GITConfig((uint8_t)(IOE_GIT_TOUCH | IOE_GIT_FTH | IOE_GIT_FOV), ENABLE);
/* Read the GPIO_IT_STA to clear all pending bits if any */
I2C_ReadDeviceRegister(IOE_REG_GPIO_INT_STA);
/* If all OK return IOE_OK */
return IOE_OK;
}
/**
* @brief Returns Status and positions of the Touch Panel.
* @param None
* @retval Pointer to TP_STATE structure holding Touch Panel information.
*/
TP_STATE* IOE_TP_GetState(void)
{
uint32_t xDiff, yDiff , x , y;
static uint32_t _x = 0, _y = 0;
/* Check if the Touch detect event happened */
TP_State.TouchDetected = (I2C_ReadDeviceRegister(IOE_REG_TP_CTRL) & 0x80);
if(TP_State.TouchDetected)
{
x = IOE_TP_Read_X();
y = IOE_TP_Read_Y();
xDiff = x > _x? (x - _x): (_x - x);
yDiff = y > _y? (y - _y): (_y - y);
if (xDiff + yDiff > 5)
{
_x = x;
_y = y;
}
}
/* Update the X position */
TP_State.X = _x;
/* Update the Y position */
TP_State.Y = _y;
/* Update the Z Pression index */
TP_State.Z = IOE_TP_Read_Z();
/* Clear the interrupt pending bit and enable the FIFO again */
I2C_WriteDeviceRegister(IOE_REG_FIFO_STA, 0x01);
I2C_WriteDeviceRegister(IOE_REG_FIFO_STA, 0x00);
/* Return pointer to the updated structure */
return &TP_State;
}
/**
* @brief Checks the selected Global interrupt source pending bit
* @param Global_IT: the Global interrupt source to be checked, could be:
* @arg Global_IT_ADC : ADC interrupt
* @arg Global_IT_FE : Touch Panel Controller FIFO Error interrupt
* @arg Global_IT_FF : Touch Panel Controller FIFO Full interrupt
* @arg Global_IT_FOV : Touch Panel Controller FIFO Overrun interrupt
* @arg Global_IT_FTH : Touch Panel Controller FIFO Threshold interrupt
* @arg Global_IT_TOUCH : Touch Panel Controller Touch Detected interrupt
* @retval Status of the checked flag. Could be SET or RESET.
*/
FlagStatus IOE_GetGITStatus(uint8_t Global_IT)
{
__IO uint8_t tmp = 0;
/* Get the Interrupt status */
tmp = I2C_ReadDeviceRegister(IOE_REG_INT_STA);
if ((tmp & (uint8_t)Global_IT) != 0)
{
return SET;
}
else
{
return RESET;
}
}
/**
* @brief Clears the selected Global interrupt pending bit(s)
* @param Global_IT: the Global interrupt to be cleared, could be any combination
* of the following values:
* @arg Global_IT_ADC : ADC interrupt
* @arg Global_IT_FE : Touch Panel Controller FIFO Error interrupt
* @arg Global_IT_FF : Touch Panel Controller FIFO Full interrupt
* @arg Global_IT_FOV : Touch Panel Controller FIFO Overrun interrupt
* @arg Global_IT_FTH : Touch Panel Controller FIFO Threshold interrupt
* @arg Global_IT_TOUCH : Touch Panel Controller Touch Detected interrupt
* @retval IOE_OK: if all initializations are OK. Other value if error.
*/
uint8_t IOE_ClearGITPending(uint8_t Global_IT)
{
/* Write 1 to the bits that have to be cleared */
I2C_WriteDeviceRegister(IOE_REG_INT_STA, Global_IT);
/* If all OK return IOE_OK */
return IOE_OK;
}
/**
* @brief Checks if the IOE device is correctly configured and
* communicates correctly ont the I2C bus.
* @param None
* @retval IOE_OK if IOE is operational. Other value if failure.
*/
uint8_t IOE_IsOperational(void)
{
/* Return Error if the ID is not correct */
if( IOE_ReadID() != (uint16_t)STMPE811_ID )
{
/* Check if a Timeout occurred */
if (IOE_TimeOut == 0)
{
return(IOE_TimeoutUserCallback());
}
else
{
return IOE_FAILURE; /* ID is not Correct */
}
}
else
{
return IOE_OK; /* ID is correct */
}
}
/**
* @brief Resets the IO Expander by Software (SYS_CTRL1, RESET bit).
* @param None
* @retval IOE_OK: if all initializations are OK. Other value if error.
*/
uint8_t IOE_Reset(void)
{
/* Power Down the IO_Expander */
I2C_WriteDeviceRegister(IOE_REG_SYS_CTRL1, 0x02);
/* wait for a delay to insure registers erasing */
_delay_(2);
/* Power On the Codec after the power off => all registers are reinitialized*/
I2C_WriteDeviceRegister(IOE_REG_SYS_CTRL1, 0x00);
/* If all OK return IOE_OK */
return IOE_OK;
}
/**
* @brief Reads the IOE device ID.
* @param None
* @retval The Device ID (two bytes).
*/
uint16_t IOE_ReadID(void)
{
uint16_t tmp = 0;
/* Read device ID */
tmp = I2C_ReadDeviceRegister(0);
tmp = (uint32_t)(tmp << 8);
tmp |= (uint32_t)I2C_ReadDeviceRegister(1);
/* Return the ID */
return (uint16_t)tmp;
}
/**
* @brief Configures the selected IO Expander functionalities.
* @param Fct: the functions to be configured. could be any
* combination of the following values:
* @arg IOE_IO_FCT : IO function
* @arg IOE_TP_FCT : Touch Panel function
* @arg IOE_ADC_FCT : ADC function
* @param NewState: can be ENABLE pr DISABLE
* @retval IOE_OK: if all initializations are OK. Other value if error.
*/
uint8_t IOE_FnctCmd(uint8_t Fct, FunctionalState NewState)
{
uint8_t tmp = 0;
/* Get the register value */
tmp = I2C_ReadDeviceRegister(IOE_REG_SYS_CTRL2);
if (NewState != DISABLE)
{
/* Set the Functionalities to be Enabled */
tmp &= ~(uint8_t)Fct;
}
else
{
/* Set the Functionalities to be Disabled */
tmp |= (uint8_t)Fct;
}
/* Set the register value */
I2C_WriteDeviceRegister(IOE_REG_SYS_CTRL2, tmp);
/* If all OK return IOE_OK */
return IOE_OK;
}
/**
* @brief Enables or disables the Global interrupt.
* @param NewState: could be ENABLE or DISABLE.
* @retval IOE_OK: if all initializations are OK. Other value if error.
*/
uint8_t IOE_GITCmd(FunctionalState NewState)
{
uint8_t tmp = 0;
/* Read the Interrupt Control register */
tmp = I2C_ReadDeviceRegister(IOE_REG_INT_CTRL);
if (NewState != DISABLE)
{
/* Set the global interrupts to be Enabled */
tmp |= (uint8_t)IOE_GIT_EN;
}
else
{
/* Set the global interrupts to be Disabled */
tmp &= ~(uint8_t)IOE_GIT_EN;
}
/* Write Back the Interrupt Control register */
I2C_WriteDeviceRegister(IOE_REG_INT_CTRL, tmp);
/* If all OK return IOE_OK */
return IOE_OK;
}
/**
* @brief Configures the selected source to generate or not a global interrupt
* @param Global_IT: the interrupt source to be configured, could be:
* @arg Global_IT_ADC : ADC interrupt
* @arg Global_IT_FE : Touch Panel Controller FIFO Error interrupt
* @arg Global_IT_FF : Touch Panel Controller FIFO Full interrupt
* @arg Global_IT_FOV : Touch Panel Controller FIFO Overrun interrupt
* @arg Global_IT_FTH : Touch Panel Controller FIFO Threshold interrupt
* @arg Global_IT_TOUCH : Touch Panel Controller Touch Detected interrupt
* @param NewState: can be ENABLE pr DISABLE
* @retval IOE_OK: if all initializations are OK. Other value if error.
*/
uint8_t IOE_GITConfig(uint8_t Global_IT, FunctionalState NewState)
{
uint8_t tmp = 0;
/* Get the current value of the INT_EN register */
tmp = I2C_ReadDeviceRegister(IOE_REG_INT_EN);
if (NewState != DISABLE)
{
/* Set the interrupts to be Enabled */
tmp |= (uint8_t)Global_IT;
}
else
{
/* Set the interrupts to be Disabled */
tmp &= ~(uint8_t)Global_IT;
}
/* Set the register */
I2C_WriteDeviceRegister(IOE_REG_INT_EN, tmp);
/* If all OK return IOE_OK */
return IOE_OK;
}
/**
* @brief Configures the touch Panel Controller (Single point detection)
* @param None
* @retval IOE_OK if all initializations are OK. Other value if error.
*/
uint8_t IOE_TP_Config(void)
{
/* Enable touch Panel functionality */
IOE_FnctCmd(IOE_TP_FCT, ENABLE);
/* Select Sample Time, bit number and ADC Reference */
I2C_WriteDeviceRegister(IOE_REG_ADC_CTRL1, 0x49);
/* Wait for ~20 ms */
_delay_(2);
/* Select the ADC clock speed: 3.25 MHz */
I2C_WriteDeviceRegister(IOE_REG_ADC_CTRL2, 0x01);
/* Select TSC pins in non default mode */
IOE_IOAFConfig((uint8_t)TOUCH_IO_ALL, DISABLE);
/* Select 2 nF filter capacitor */
I2C_WriteDeviceRegister(IOE_REG_TP_CFG, 0x9A);
/* Select single point reading */
I2C_WriteDeviceRegister(IOE_REG_FIFO_TH, 0x01);
/* Write 0x01 to clear the FIFO memory content. */
I2C_WriteDeviceRegister(IOE_REG_FIFO_STA, 0x01);
/* Write 0x00 to put the FIFO back into operation mode */
I2C_WriteDeviceRegister(IOE_REG_FIFO_STA, 0x00);
/* set the data format for Z value: 7 fractional part and 1 whole part */
I2C_WriteDeviceRegister(IOE_REG_TP_FRACT_XYZ, 0x01);
/* set the driving capability of the device for TSC pins: 50mA */
I2C_WriteDeviceRegister(IOE_REG_TP_I_DRIVE, 0x01);
/* Use no tracking index, touch-panel controller operation mode (XYZ) and
enable the TSC */
I2C_WriteDeviceRegister(IOE_REG_TP_CTRL, 0x03);
/* Clear all the status pending bits */
I2C_WriteDeviceRegister(IOE_REG_INT_STA, 0xFF);
/* Initialize the TS structure to their default values */
TP_State.TouchDetected = TP_State.X = TP_State.Y = TP_State.Z = 0;
/* All configuration done */
return IOE_OK;
}
/**
* @brief Configures the selected pin to be in Alternate function or not.
* @param IO_Pin: IO_Pin_x, Where x can be from 0 to 7.
* @param NewState: State of the AF for the selected pin, could be
* ENABLE or DISABLE.
* @retval IOE_OK: if all initializations are OK. Other value if error.
*/
uint8_t IOE_IOAFConfig(uint8_t IO_Pin, FunctionalState NewState)
{
uint8_t tmp = 0;
/* Get the current state of the GPIO_AF register */
tmp = I2C_ReadDeviceRegister(IOE_REG_GPIO_AF);
if (NewState != DISABLE)
{
/* Enable the selected pins alternate function */
tmp |= (uint8_t)IO_Pin;
}
else
{
/* Disable the selected pins alternate function */
tmp &= ~(uint8_t)IO_Pin;
}
/* Write back the new value in GPIO_AF register */
I2C_WriteDeviceRegister(IOE_REG_GPIO_AF, tmp);
/* If all OK return IOE_OK */
return IOE_OK;
}
/**
* @brief Writes a value in a register of the device through I2C.
* @param RegisterAddr: The target register address
* @param RegisterValue: The target register value to be written
* @retval IOE_OK: if all operations are OK. Other value if error.
*/
uint8_t I2C_DMA_WriteDeviceRegister(uint8_t RegisterAddr, uint8_t RegisterValue)
{
uint32_t read_verif = 0;
uint8_t IOE_BufferTX = 0;
/* Get Value to be written */
IOE_BufferTX = RegisterValue;
/* Configure DMA Peripheral */
IOE_DMA_Config(IOE_DMA_TX, (uint8_t*)(&IOE_BufferTX));
/* Enable the I2C peripheral */
I2C_GenerateSTART(IOE_I2C, ENABLE);
/* Test on SB Flag */
IOE_TimeOut = TIMEOUT_MAX;
while (I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_SB) == RESET)
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Transmit the slave address and enable writing operation */
I2C_Send7bitAddress(IOE_I2C, IOE_ADDR, I2C_Direction_Transmitter);
/* Test on ADDR Flag */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Transmit the first address for r/w operations */
I2C_SendData(IOE_I2C, RegisterAddr);
/* Test on TXE FLag (data dent) */
IOE_TimeOut = TIMEOUT_MAX;
while ((!I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_TXE)) && (!I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_BTF)))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Enable I2C DMA request */
I2C_DMACmd(IOE_I2C,ENABLE);
/* Enable DMA TX Channel */
DMA_Cmd(IOE_DMA_TX_STREAM, ENABLE);
/* Wait until DMA Transfer Complete */
IOE_TimeOut = TIMEOUT_MAX;
while (!DMA_GetFlagStatus(IOE_DMA_TX_STREAM,IOE_DMA_TX_TCFLAG))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Wait until BTF Flag is set before generating STOP */
IOE_TimeOut = 0xFF * TIMEOUT_MAX;
while ((!I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_BTF)))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Send STOP Condition */
I2C_GenerateSTOP(IOE_I2C, ENABLE);
/* Disable DMA TX Channel */
DMA_Cmd(IOE_DMA_TX_STREAM, DISABLE);
/* Disable I2C DMA request */
I2C_DMACmd(IOE_I2C,DISABLE);
/* Clear DMA TX Transfer Complete Flag */
DMA_ClearFlag(IOE_DMA_TX_STREAM,IOE_DMA_TX_TCFLAG);
#ifdef VERIFY_WRITTENDATA
/* Verify (if needed) that the loaded data is correct */
/* Read the just written register*/
read_verif = I2C_ReadDeviceRegister(RegisterAddr);
/* Load the register and verify its value */
if (read_verif != RegisterValue)
{
/* Control data wrongly transferred */
read_verif = IOE_FAILURE;
}
else
{
/* Control data correctly transferred */
read_verif = 0;
}
#endif
/* Return the verifying value: 0 (Passed) or 1 (Failed) */
return read_verif;
}
/**
* @brief Reads a register of the device through I2C.
* @param RegisterAddr: The target register address (between 00x and 0x24)
* @retval The value of the read register (0xAA if Timeout occurred)
*/
uint8_t I2C_DMA_ReadDeviceRegister(uint8_t RegisterAddr)
{
uint8_t IOE_BufferRX[2] = {0x00, 0x00};
/* Configure DMA Peripheral */
IOE_DMA_Config(IOE_DMA_RX, (uint8_t*)IOE_BufferRX);
/* Enable DMA NACK automatic generation */
I2C_DMALastTransferCmd(IOE_I2C, ENABLE);
/* Enable the I2C peripheral */
I2C_GenerateSTART(IOE_I2C, ENABLE);
/* Test on SB Flag */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_SB))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Send device address for write */
I2C_Send7bitAddress(IOE_I2C, IOE_ADDR, I2C_Direction_Transmitter);
/* Test on ADDR Flag */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Send the device's internal address to write to */
I2C_SendData(IOE_I2C, RegisterAddr);
/* Test on TXE FLag (data dent) */
IOE_TimeOut = TIMEOUT_MAX;
while ((!I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_TXE)) && (!I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_BTF)))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Send START condition a second time */
I2C_GenerateSTART(IOE_I2C, ENABLE);
/* Test on SB Flag */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_SB))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Send IOExpander address for read */
I2C_Send7bitAddress(IOE_I2C, IOE_ADDR, I2C_Direction_Receiver);
/* Test on ADDR Flag */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Enable I2C DMA request */
I2C_DMACmd(IOE_I2C,ENABLE);
/* Enable DMA RX Channel */
DMA_Cmd(IOE_DMA_RX_STREAM, ENABLE);
/* Wait until DMA Transfer Complete */
IOE_TimeOut = 2 * TIMEOUT_MAX;
while (!DMA_GetFlagStatus(IOE_DMA_RX_STREAM,IOE_DMA_RX_TCFLAG))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Send STOP Condition */
I2C_GenerateSTOP(IOE_I2C, ENABLE);
/* Disable DMA RX Channel */
DMA_Cmd(IOE_DMA_RX_STREAM, DISABLE);
/* Disable I2C DMA request */
I2C_DMACmd(IOE_I2C,DISABLE);
/* Clear DMA RX Transfer Complete Flag */
DMA_ClearFlag(IOE_DMA_RX_STREAM,IOE_DMA_RX_TCFLAG);
/* return a pointer to the IOE_Buffer */
return (uint8_t)IOE_BufferRX[0];
}
/**
* @brief Reads a buffer of 2 bytes from the device registers.
* @param RegisterAddr: The target register address (between 00x and 0x24)
* @retval A pointer to the buffer containing the two returned bytes (in halfword).
*/
uint16_t I2C_DMA_ReadDataBuffer(uint32_t RegisterAddr)
{
uint8_t tmp= 0;
uint8_t IOE_BufferRX[2] = {0x00, 0x00};
/* Configure DMA Peripheral */
IOE_DMA_Config(IOE_DMA_RX, (uint8_t*)IOE_BufferRX);
/* Enable DMA NACK automatic generation */
I2C_DMALastTransferCmd(IOE_I2C, ENABLE);
/* Enable the I2C peripheral */
I2C_GenerateSTART(IOE_I2C, ENABLE);
/* Test on SB Flag */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_SB))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Send device address for write */
I2C_Send7bitAddress(IOE_I2C, IOE_ADDR, I2C_Direction_Transmitter);
/* Test on ADDR Flag */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Send the device's internal address to write to */
I2C_SendData(IOE_I2C, RegisterAddr);
/* Test on TXE FLag (data dent) */
IOE_TimeOut = TIMEOUT_MAX;
while ((!I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_TXE)) && (!I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_BTF)))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Send START condition a second time */
I2C_GenerateSTART(IOE_I2C, ENABLE);
/* Test on SB Flag */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_SB))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Send IO Expander address for read */
I2C_Send7bitAddress(IOE_I2C, IOE_ADDR, I2C_Direction_Receiver);
/* Test on ADDR Flag */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Enable I2C DMA request */
I2C_DMACmd(IOE_I2C,ENABLE);
/* Enable DMA RX Channel */
DMA_Cmd(IOE_DMA_RX_STREAM, ENABLE);
/* Wait until DMA Transfer Complete */
IOE_TimeOut = 2 * TIMEOUT_MAX;
while (!DMA_GetFlagStatus(IOE_DMA_RX_STREAM, IOE_DMA_RX_TCFLAG))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Send STOP Condition */
I2C_GenerateSTOP(IOE_I2C, ENABLE);
/* Disable DMA RX Channel */
DMA_Cmd(IOE_DMA_RX_STREAM, DISABLE);
/* Disable I2C DMA request */
I2C_DMACmd(IOE_I2C,DISABLE);
/* Clear DMA RX Transfer Complete Flag */
DMA_ClearFlag(IOE_DMA_RX_STREAM,IOE_DMA_RX_TCFLAG);
/* Reorganize received data */
tmp = IOE_BufferRX[0];
IOE_BufferRX[0] = IOE_BufferRX[1];
IOE_BufferRX[1] = tmp;
/* return the data */
return (uint16_t) ((uint16_t)IOE_BufferRX[0] | (uint16_t)IOE_BufferRX[1]<< 8);
}
/**
* @brief Return Touch Panel X position value
* @param None
* @retval X position.
*/
static uint16_t IOE_TP_Read_X(void)
{
int32_t x, xr;
/* Read x value from DATA_X register */
x = I2C_ReadDataBuffer(IOE_REG_TP_DATA_X);
/* x value first correction */
if(x <= 3000)
{
x = 3870 - x;
}
else
{
x = 3800 - x;
}
/* x value second correction */
xr = x / 15;
/* return x position value */
if(xr <= 0)
{
xr = 0;
}
else if (xr > 240)
{
xr = 239;
}
else
{}
return (uint16_t)(xr);
}
/**
* @brief Return Touch Panel Y position value
* @param None
* @retval Y position.
*/
static uint16_t IOE_TP_Read_Y(void)
{
int32_t y, yr;
/* Read y value from DATA_Y register */
y = I2C_ReadDataBuffer(IOE_REG_TP_DATA_Y);
/* y value first correction */
y -= 360;
/* y value second correction */
yr = y / 11;
/* return y position value */
if(yr <= 0)
{
yr = 0;
}
else if (yr > 320)
{
yr = 319;
}
else
{}
return (uint16_t)(yr);
}
/**
* @brief Return Touch Panel Z position value
* @param None
* @retval Z position.
*/
static uint16_t IOE_TP_Read_Z(void)
{
uint32_t z;
/* Read z value from DATA_Z register */
z = I2C_ReadDataBuffer(IOE_REG_TP_DATA_Z);
/* return z position value */
if(z <= 0)
z = 0;
return (uint16_t)(z);
}
/**
* @brief Initializes the GPIO pins used by the IO expander.
* @param None
* @retval None
*/
static void IOE_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable IOE_I2C and IOE_I2C_GPIO_PORT & Alternate Function clocks */
RCC_APB1PeriphClockCmd(IOE_I2C_CLK, ENABLE);
RCC_AHB1PeriphClockCmd(IOE_I2C_SCL_GPIO_CLK | IOE_I2C_SDA_GPIO_CLK |
IOE_IT_GPIO_CLK, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
/* Reset IOE_I2C IP */
RCC_APB1PeriphResetCmd(IOE_I2C_CLK, ENABLE);
/* Release reset signal of IOE_I2C IP */
RCC_APB1PeriphResetCmd(IOE_I2C_CLK, DISABLE);
/* Connect PXx to I2C_SCL*/
GPIO_PinAFConfig(IOE_I2C_SCL_GPIO_PORT, IOE_I2C_SCL_SOURCE, IOE_I2C_SCL_AF);
/* Connect PXx to I2C_SDA*/
GPIO_PinAFConfig(IOE_I2C_SDA_GPIO_PORT, IOE_I2C_SDA_SOURCE, IOE_I2C_SDA_AF);
/* IOE_I2C SCL and SDA pins configuration */
GPIO_InitStructure.GPIO_Pin = IOE_I2C_SCL_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(IOE_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = IOE_I2C_SDA_PIN;
GPIO_Init(IOE_I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
}
/**
* @brief Configure the I2C Peripheral used to communicate with IO_Expanders.
* @param None
* @retval None
*/
static void IOE_I2C_Config(void)
{
I2C_InitTypeDef I2C_InitStructure;
/* If the I2C peripheral is already enabled, don't reconfigure it */
if ((IOE_I2C->CR1 & I2C_CR1_PE) == 0)
{
/* IOE_I2C configuration */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED;
/* Initialize the I2C peripheral */
I2C_Init(IOE_I2C, &I2C_InitStructure);
/* Enable the I2C peripheral */
I2C_Cmd(IOE_I2C, ENABLE);
}
}
/**
* @brief Configure the DMA Peripheral used to handle communication via I2C.
* @param None
* @retval None
*/
static void IOE_DMA_Config(IOE_DMADirection_TypeDef Direction, uint8_t* buffer)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(IOE_DMA_CLK, ENABLE);
/* Initialize the DMA_Channel member */
DMA_InitStructure.DMA_Channel = IOE_DMA_CHANNEL;
/* Initialize the DMA_PeripheralBaseAddr member */
DMA_InitStructure.DMA_PeripheralBaseAddr = IOE_I2C_DR;
/* Initialize the DMA_Memory0BaseAddr member */
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)buffer;
/* Initialize the DMA_PeripheralInc member */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
/* Initialize the DMA_MemoryInc member */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
/* Initialize the DMA_PeripheralDataSize member */
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
/* Initialize the DMA_MemoryDataSize member */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
/* Initialize the DMA_Mode member */
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
/* Initialize the DMA_Priority member */
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
/* Initialize the DMA_FIFOMode member */
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
/* Initialize the DMA_FIFOThreshold member */
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
/* Initialize the DMA_MemoryBurst member */
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
/* Initialize the DMA_PeripheralBurst member */
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
/* If using DMA for Reception */
if (Direction == IOE_DMA_RX)
{
/* Initialize the DMA_DIR member */
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
/* Initialize the DMA_BufferSize member */
DMA_InitStructure.DMA_BufferSize = 2;
DMA_DeInit(IOE_DMA_RX_STREAM);
DMA_Init(IOE_DMA_RX_STREAM, &DMA_InitStructure);
}
/* If using DMA for Transmission */
else if (Direction == IOE_DMA_TX)
{
/* Initialize the DMA_DIR member */
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
/* Initialize the DMA_BufferSize member */
DMA_InitStructure.DMA_BufferSize = 1;
DMA_DeInit(IOE_DMA_TX_STREAM);
DMA_Init(IOE_DMA_TX_STREAM, &DMA_InitStructure);
}
}
/**
* @brief Writes a value in a register of the device through I2C.
* @param RegisterAddr: The target register address
* @param RegisterValue: The target register value to be written
* @retval IOE_OK: if all operations are OK. Other value if error.
*/
uint8_t I2C_WriteDeviceRegister(uint8_t RegisterAddr, uint8_t RegisterValue)
{
uint32_t read_verif = 0;
/* Begin the configuration sequence */
I2C_GenerateSTART(IOE_I2C, ENABLE);
/* Test on EV5 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_SB))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Transmit the slave address and enable writing operation */
I2C_Send7bitAddress(IOE_I2C, IOE_ADDR, I2C_Direction_Transmitter);
/* Test on EV6 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_ADDR))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Read status register 2 to clear ADDR flag */
IOE_I2C->SR2;
/* Test on EV8_1 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_TXE))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Transmit the first address for r/w operations */
I2C_SendData(IOE_I2C, RegisterAddr);
/* Test on EV8 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_TXE))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Prepare the register value to be sent */
I2C_SendData(IOE_I2C, RegisterValue);
/* Test on EV8_2 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while ((!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_TXE)) || (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_BTF)))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* End the configuration sequence */
I2C_GenerateSTOP(IOE_I2C, ENABLE);
#ifdef VERIFY_WRITTENDATA
/* Verify (if needed) that the loaded data is correct */
/* Read the just written register*/
read_verif = IOE_I2C_ReadDeviceRegister(RegisterAddr);
/* Load the register and verify its value */
if (read_verif != RegisterValue)
{
/* Control data wrongly transferred */
read_verif = IOE_FAILURE;
}
else
{
/* Control data correctly transferred */
read_verif = 0;
}
#endif
/* Return the verifying value: 0 (Passed) or 1 (Failed) */
return read_verif;
}
/**
* @brief Reads a register of the device through I2C without DMA.
* @param RegisterAddr: The target register address (between 00x and 0x24)
* @retval The value of the read register (0xAA if Timeout occurred)
*/
uint8_t I2C_ReadDeviceRegister(uint8_t RegisterAddr)
{
uint8_t tmp = 0;
/* Enable the I2C peripheral */
I2C_GenerateSTART(IOE_I2C, ENABLE);
/* Test on EV5 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_SB))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Disable Acknowledgement */
I2C_AcknowledgeConfig(IOE_I2C, DISABLE);
/* Transmit the slave address and enable writing operation */
I2C_Send7bitAddress(IOE_I2C, IOE_ADDR, I2C_Direction_Transmitter);
/* Test on EV6 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_ADDR))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Read status register 2 to clear ADDR flag */
IOE_I2C->SR2;
/* Test on EV8 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_TXE))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Transmit the first address for r/w operations */
I2C_SendData(IOE_I2C, RegisterAddr);
/* Test on EV8 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while ((!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_TXE)) || (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_BTF)))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Regenerate a start condition */
I2C_GenerateSTART(IOE_I2C, ENABLE);
/* Test on EV5 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_SB))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Transmit the slave address and enable writing operation */
I2C_Send7bitAddress(IOE_I2C, IOE_ADDR, I2C_Direction_Receiver);
/* Test on EV6 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_ADDR))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Read status register 2 to clear ADDR flag */
IOE_I2C->SR2;
/* Test on EV7 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_RXNE))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* End the configuration sequence */
I2C_GenerateSTOP(IOE_I2C, ENABLE);
/* Load the register value */
tmp = I2C_ReceiveData(IOE_I2C);
/* Enable Acknowledgement */
I2C_AcknowledgeConfig(IOE_I2C, ENABLE);
/* Return the read value */
return tmp;
}
/**
* @brief Reads a buffer of 2 bytes from the device registers.
* @param RegisterAddr: The target register adress (between 00x and 0x24)
* @retval The data in the buffer containing the two returned bytes (in halfword).
*/
uint16_t I2C_ReadDataBuffer(uint32_t RegisterAddr)
{
uint8_t IOE_BufferRX[2] = {0x00, 0x00};
/* Enable the I2C peripheral */
I2C_GenerateSTART(IOE_I2C, ENABLE);
/* Test on EV5 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_SB))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Send device address for write */
I2C_Send7bitAddress(IOE_I2C, IOE_ADDR, I2C_Direction_Transmitter);
/* Test on EV6 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_ADDR))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Read status register 2 to clear ADDR flag */
IOE_I2C->SR2;
/* Test on EV8 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_TXE))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Send the device's internal address to write to */
I2C_SendData(IOE_I2C, RegisterAddr);
/* Send START condition a second time */
I2C_GenerateSTART(IOE_I2C, ENABLE);
/* Test on EV5 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_SB))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Send IO Expander address for read */
I2C_Send7bitAddress(IOE_I2C, IOE_ADDR, I2C_Direction_Receiver);
/* Test on EV6 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_ADDR))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Disable Acknowledgement and set Pos bit */
I2C_AcknowledgeConfig(IOE_I2C, DISABLE);
I2C_NACKPositionConfig(IOE_I2C, I2C_NACKPosition_Next);
/* Read status register 2 to clear ADDR flag */
IOE_I2C->SR2;
/* Test on EV7 and clear it */
IOE_TimeOut = TIMEOUT_MAX;
while (!I2C_GetFlagStatus(IOE_I2C, I2C_FLAG_BTF))
{
if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback());
}
/* Send STOP Condition */
I2C_GenerateSTOP(IOE_I2C, ENABLE);
/* Read the first byte from the IO Expander */
IOE_BufferRX[1] = I2C_ReceiveData(IOE_I2C);
/* Read the second byte from the IO Expander */
IOE_BufferRX[0] = I2C_ReceiveData(IOE_I2C);
/* Enable Acknowledgement and reset POS bit to be ready for another reception */
I2C_AcknowledgeConfig(IOE_I2C, ENABLE);
I2C_NACKPositionConfig(IOE_I2C, I2C_NACKPosition_Current);
/* return the data */
return ((uint16_t) IOE_BufferRX[0] | ((uint16_t)IOE_BufferRX[1]<< 8));
}
#ifndef USE_TIMEOUT_USER_CALLBACK
/**
* @brief IOE_TIMEOUT_UserCallback
* @param None
* @retval 0
*/
uint8_t IOE_TimeoutUserCallback(void)
{
I2C_InitTypeDef I2C_InitStructure;
I2C_GenerateSTOP(IOE_I2C, ENABLE);
I2C_SoftwareResetCmd(IOE_I2C, ENABLE);
I2C_SoftwareResetCmd(IOE_I2C, DISABLE);
IOE_GPIO_Config();
/* CODEC_I2C peripheral configuration */
I2C_DeInit(IOE_I2C);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED;
/* Enable the I2C peripheral */
I2C_Cmd(IOE_I2C, ENABLE);
I2C_Init(IOE_I2C, &I2C_InitStructure);
return 0;
}
#endif /* !USE_TIMEOUT_USER_CALLBACK */
#ifndef USE_Delay
/**
* @brief Inserts a delay time.
* @param nCount: specifies the delay time length.
* @retval None
*/
static void delay(__IO uint32_t nCount)
{
__IO uint32_t index = 0;
for(index = (100000 * nCount); index != 0; index--)
{
}
}
#endif /* USE_Delay */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/