362 lines
10 KiB
C
362 lines
10 KiB
C
|
/****************************************************************************
|
||
|
**
|
||
|
** Copyright (C) 2020 MikroElektronika d.o.o.
|
||
|
** Contact: https://www.mikroe.com/contact
|
||
|
**
|
||
|
** This file is part of the mikroSDK package
|
||
|
**
|
||
|
** Commercial License Usage
|
||
|
**
|
||
|
** Licensees holding valid commercial NECTO compilers AI licenses may use this
|
||
|
** file in accordance with the commercial license agreement provided with the
|
||
|
** Software or, alternatively, in accordance with the terms contained in
|
||
|
** a written agreement between you and The mikroElektronika Company.
|
||
|
** For licensing terms and conditions see
|
||
|
** https://www.mikroe.com/legal/software-license-agreement.
|
||
|
** For further information use the contact form at
|
||
|
** https://www.mikroe.com/contact.
|
||
|
**
|
||
|
**
|
||
|
** GNU Lesser General Public License Usage
|
||
|
**
|
||
|
** Alternatively, this file may be used for
|
||
|
** non-commercial projects under the terms of the GNU Lesser
|
||
|
** General Public License version 3 as published by the Free Software
|
||
|
** Foundation: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||
|
**
|
||
|
** The above copyright notice and this permission notice shall be
|
||
|
** included in all copies or substantial portions of the Software.
|
||
|
**
|
||
|
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
|
** OF MERCHANTABILITY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||
|
** TO THE WARRANTIES FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||
|
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||
|
** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
||
|
** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||
|
** OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
**
|
||
|
****************************************************************************/
|
||
|
|
||
|
/*!
|
||
|
* @file ft5xx6.c
|
||
|
* @brief FT5xx6 Touch Controller Driver.
|
||
|
*/
|
||
|
|
||
|
#include "ft5xx6.h"
|
||
|
#include "drv_digital_out.h"
|
||
|
#include "drv_digital_in.h"
|
||
|
|
||
|
/**
|
||
|
* @brief FT5xx6 Events Definition.
|
||
|
* @details Events code definition depending on the family of touch controller.
|
||
|
*/
|
||
|
const ft5xx6_controller_t FT5X06_CONTROLLER =
|
||
|
{
|
||
|
{
|
||
|
{ 0x00, TP_EVENT_GEST_NONE },
|
||
|
{ 0x10, TP_EVENT_GEST_LEFT },
|
||
|
{ 0x18, TP_EVENT_GEST_RIGHT },
|
||
|
{ 0x1C, TP_EVENT_GEST_UP },
|
||
|
{ 0x14, TP_EVENT_GEST_DOWN },
|
||
|
{ 0x48, TP_EVENT_GEST_ZOOM_IN },
|
||
|
{ 0x49, TP_EVENT_GEST_ZOOM_OUT }
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const ft5xx6_controller_t FT5X16_CONTROLLER =
|
||
|
{
|
||
|
{
|
||
|
{ 0x00, TP_EVENT_GEST_NONE },
|
||
|
{ 0x10, TP_EVENT_GEST_LEFT },
|
||
|
{ 0x18, TP_EVENT_GEST_RIGHT },
|
||
|
{ 0x1C, TP_EVENT_GEST_UP },
|
||
|
{ 0x14, TP_EVENT_GEST_DOWN },
|
||
|
{ 0x48, TP_EVENT_GEST_ZOOM_IN },
|
||
|
{ 0x49, TP_EVENT_GEST_ZOOM_OUT }
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const ft5xx6_controller_t FT5X26_CONTROLLER =
|
||
|
{
|
||
|
{
|
||
|
{ 0x00, TP_EVENT_GEST_NONE },
|
||
|
{ 0x1C, TP_EVENT_GEST_LEFT },
|
||
|
{ 0x14, TP_EVENT_GEST_RIGHT },
|
||
|
{ 0x10, TP_EVENT_GEST_UP },
|
||
|
{ 0x18, TP_EVENT_GEST_DOWN },
|
||
|
{ 0x48, TP_EVENT_GEST_ZOOM_IN },
|
||
|
{ 0x49, TP_EVENT_GEST_ZOOM_OUT }
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const ft5xx6_controller_t FT5X46_CONTROLLER =
|
||
|
{
|
||
|
{
|
||
|
{ 0x00, TP_EVENT_GEST_NONE },
|
||
|
{ 0x1C, TP_EVENT_GEST_LEFT },
|
||
|
{ 0x14, TP_EVENT_GEST_RIGHT },
|
||
|
{ 0x10, TP_EVENT_GEST_UP },
|
||
|
{ 0x18, TP_EVENT_GEST_DOWN },
|
||
|
{ 0x48, TP_EVENT_GEST_ZOOM_IN },
|
||
|
{ 0x49, TP_EVENT_GEST_ZOOM_OUT }
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @brief FT5xx6 Pressure Coordinates Read Function.
|
||
|
* @details This function reads the coordinates of pressed touch point/points.
|
||
|
* @param[out] ctx : FT5xx6 context object. See #ft5xx6_t structure definition
|
||
|
* for detailed explanation.
|
||
|
* @return @li @c 0 - OK,
|
||
|
* @li @c 5 - Number of pressed touches is out of range.
|
||
|
* See #tp_err_t structure definition for detailed explanation.
|
||
|
*/
|
||
|
static tp_err_t
|
||
|
ft5xx6_read_press_coordinates( ft5xx6_t * ctx );
|
||
|
|
||
|
/**
|
||
|
* @brief FT5xx6 Gesture Read Function.
|
||
|
* @details This function reads the gesture ID and allows user to see the slide
|
||
|
* direction.
|
||
|
* @param[out] ctx : FT5xx6 context object. See #ft5xx6_t structure definition
|
||
|
* for detailed explanation.
|
||
|
* @return Nothing.
|
||
|
*/
|
||
|
static void
|
||
|
ft5xx6_read_gesture( ft5xx6_t * ctx );
|
||
|
|
||
|
void
|
||
|
ft5xx6_cfg_setup( ft5xx6_cfg_t * cfg, const ft5xx6_controller_t * controller )
|
||
|
{
|
||
|
i2c_master_configure_default( &cfg->i2c_cfg );
|
||
|
|
||
|
cfg->int_pin = HAL_PIN_NC;
|
||
|
cfg->controller = controller;
|
||
|
}
|
||
|
|
||
|
tp_err_t
|
||
|
ft5xx6_init( ft5xx6_t * ctx, ft5xx6_cfg_t * cfg, tp_drv_t * drv )
|
||
|
{
|
||
|
// digital_out_t scl_pin;
|
||
|
// digital_in_t sda_pin;
|
||
|
|
||
|
// ** Linking problem for functions with different types of arguments.
|
||
|
tp_event_t ( * tmp_ptr1 )( ft5xx6_t * );
|
||
|
void ( * tmp_ptr2 )( ft5xx6_t *, tp_touch_item_t * );
|
||
|
void ( * tmp_ptr3 )( ft5xx6_t *, tp_event_t * );
|
||
|
tp_err_t ( * tmp_ptr4 )( ft5xx6_t * );
|
||
|
|
||
|
/*digital_out_init( &scl_pin, cfg->i2c_cfg.scl );
|
||
|
digital_in_init( &sda_pin, cfg->i2c_cfg.sda );
|
||
|
digital_out_high( &scl_pin );
|
||
|
|
||
|
while ( 0 == digital_in_read( &sda_pin ) )
|
||
|
{
|
||
|
digital_out_low( &scl_pin );
|
||
|
Delay_10us( );
|
||
|
digital_out_high( &scl_pin );
|
||
|
Delay_10us( );
|
||
|
}*/
|
||
|
|
||
|
if ( i2c_master_open( &ctx->i2c, &cfg->i2c_cfg ) == I2C_MASTER_ERROR )
|
||
|
{
|
||
|
return TP_ERR_INIT_DRV;
|
||
|
}
|
||
|
|
||
|
i2c_master_set_slave_address( &ctx->i2c, FT5XX6_I2C_ADDR );
|
||
|
i2c_master_set_speed( &ctx->i2c, I2C_MASTER_SPEED_STANDARD );
|
||
|
i2c_master_set_timeout( &ctx->i2c, 0 );
|
||
|
|
||
|
if ( digital_in_init( &ctx->int_pin, cfg->int_pin ) == DIGITAL_IN_UNSUPPORTED_PIN )
|
||
|
{
|
||
|
return TP_ERR_UNSUPPORTED_PIN;
|
||
|
}
|
||
|
|
||
|
ctx->controller = cfg->controller;
|
||
|
|
||
|
drv->tp_press_detect_f = ft5xx6_press_detect;
|
||
|
drv->tp_press_coordinates_f = ft5xx6_press_coordinates;
|
||
|
drv->tp_gesture_f = ft5xx6_gesture;
|
||
|
drv->tp_process_f = ft5xx6_process;
|
||
|
|
||
|
return TP_OK;
|
||
|
|
||
|
// **
|
||
|
tmp_ptr1( NULL );
|
||
|
tmp_ptr2( NULL, NULL );
|
||
|
tmp_ptr3( NULL, NULL );
|
||
|
tmp_ptr4( NULL );
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ft5xx6_default_cfg( ft5xx6_t * ctx )
|
||
|
{
|
||
|
ft5xx6_run_mode_setup( ctx, FT5XX6_RUN_MODE_CFG );
|
||
|
ft5xx6_dev_mode_setup( ctx, FT5XX6_DEV_MODE_NORMAL );
|
||
|
ft5xx6_generic_write( ctx, FT5XX6_REG_IVT_TO_HOST_STATUS, FT5XX6_INT_MODE_POLLING );
|
||
|
ft5xx6_run_mode_setup( ctx, FT5XX6_RUN_MODE_WORK );
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ft5xx6_generic_write( ft5xx6_t * ctx, uint8_t reg_addr, uint8_t data_in )
|
||
|
{
|
||
|
uint8_t tmp_data[ 2 ];
|
||
|
|
||
|
tmp_data[ 0 ] = reg_addr;
|
||
|
tmp_data[ 1 ] = data_in;
|
||
|
|
||
|
i2c_master_write( &ctx->i2c, tmp_data, 2 );
|
||
|
}
|
||
|
|
||
|
uint8_t
|
||
|
ft5xx6_generic_read_single( ft5xx6_t * ctx, uint8_t reg_addr )
|
||
|
{
|
||
|
uint8_t tmp_data;
|
||
|
|
||
|
tmp_data = reg_addr;
|
||
|
|
||
|
i2c_master_write_then_read( &ctx->i2c, &tmp_data, 1, &tmp_data, 1 );
|
||
|
|
||
|
return tmp_data;
|
||
|
}
|
||
|
|
||
|
tp_err_t
|
||
|
ft5xx6_generic_read_multiple( ft5xx6_t * ctx, uint8_t reg_addr,
|
||
|
uint8_t * data_out, uint16_t n_bytes )
|
||
|
{
|
||
|
uint8_t tmp_data;
|
||
|
|
||
|
if ( ( n_bytes < FT5XX6_N_DATA_TRANSFER_MIN ) ||
|
||
|
( n_bytes > FT5XX6_N_DATA_TRANSFER_MAX ) )
|
||
|
{
|
||
|
return TP_ERR_N_DATA;
|
||
|
}
|
||
|
|
||
|
tmp_data = reg_addr;
|
||
|
|
||
|
i2c_master_write_then_read( &ctx->i2c, &tmp_data, 1, data_out, n_bytes );
|
||
|
|
||
|
return TP_OK;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ft5xx6_dev_mode_setup( ft5xx6_t * ctx, ft5xx6_dev_mode_t mode )
|
||
|
{
|
||
|
ft5xx6_generic_write( ctx, FT5XX6_REG_DEVICE_MODE, mode << FT5XX6_OFFSET_DEV_MODE );
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ft5xx6_run_mode_setup( ft5xx6_t * ctx, ft5xx6_run_mode_t mode )
|
||
|
{
|
||
|
ft5xx6_generic_write( ctx, FT5XX6_REG_RUNNING_STATE, mode );
|
||
|
}
|
||
|
|
||
|
tp_event_t
|
||
|
ft5xx6_press_detect( ft5xx6_t * ctx )
|
||
|
{
|
||
|
return ctx->press_det;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ft5xx6_press_coordinates( ft5xx6_t * ctx, tp_touch_item_t * touch_item )
|
||
|
{
|
||
|
touch_item->n_touches = ctx->touch.n_touches;
|
||
|
|
||
|
for ( uint8_t idx = 0; idx < ctx->touch.n_touches; idx++ )
|
||
|
{
|
||
|
touch_item->point[ idx ].coord_x = ctx->touch.point[ idx ].coord_x;
|
||
|
touch_item->point[ idx ].coord_y = ctx->touch.point[ idx ].coord_y;
|
||
|
|
||
|
touch_item->point[ idx ].event = ctx->touch.point[ idx ].event;
|
||
|
touch_item->point[ idx ].id = ctx->touch.point[ idx ].id;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ft5xx6_gesture( ft5xx6_t * ctx, tp_event_t * event )
|
||
|
{
|
||
|
*event = ctx->gesture;
|
||
|
}
|
||
|
|
||
|
tp_err_t
|
||
|
ft5xx6_process( ft5xx6_t * ctx )
|
||
|
{
|
||
|
tp_err_t status;
|
||
|
|
||
|
status = ft5xx6_read_press_coordinates( ctx );
|
||
|
|
||
|
if ( ( status == TP_OK ) && ( ctx->press_det == TP_EVENT_PRESS_DET ) )
|
||
|
{
|
||
|
ft5xx6_read_gesture( ctx );
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
static tp_err_t
|
||
|
ft5xx6_read_press_coordinates( ft5xx6_t * ctx )
|
||
|
{
|
||
|
if ( !digital_in_read( &ctx->int_pin ) )
|
||
|
{
|
||
|
ctx->touch.n_touches = ft5xx6_generic_read_single( ctx, FT5XX6_REG_TD_STATUS );
|
||
|
|
||
|
if ( ctx->touch.n_touches > TP_N_TOUCHES_MAX )
|
||
|
{
|
||
|
return TP_ERR_N_TOUCHES;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
uint8_t read_data[ 4 ];
|
||
|
uint8_t touch_addr = FT5XX6_REG_TOUCH1_XH;
|
||
|
|
||
|
for ( uint8_t idx = 0; idx < ctx->touch.n_touches; idx++ )
|
||
|
{
|
||
|
ft5xx6_generic_read_multiple( ctx, touch_addr, read_data, 4 );
|
||
|
|
||
|
ctx->touch.point[ idx ].coord_x = read_data[ 0 ];
|
||
|
ctx->touch.point[ idx ].coord_x <<= 8;
|
||
|
ctx->touch.point[ idx ].coord_x |= read_data[ 1 ];
|
||
|
ctx->touch.point[ idx ].coord_x &= FT5XX6_MASK_PRESS_COORD;
|
||
|
|
||
|
ctx->touch.point[ idx ].coord_y = read_data[ 2 ];
|
||
|
ctx->touch.point[ idx ].coord_y <<= 8;
|
||
|
ctx->touch.point[ idx ].coord_y |= read_data[ 3 ];
|
||
|
ctx->touch.point[ idx ].coord_y &= FT5XX6_MASK_PRESS_COORD;
|
||
|
|
||
|
ctx->touch.point[ idx ].event = read_data[ 0 ] >> FT5XX6_OFFSET_PRESS_EVENT;
|
||
|
ctx->touch.point[ idx ].id = read_data[ 2 ] >> FT5XX6_OFFSET_PRESS_ID;
|
||
|
|
||
|
touch_addr += FT5XX6_OFFSET_TOUCH_READING;
|
||
|
}
|
||
|
|
||
|
ctx->press_det = TP_EVENT_PRESS_DET;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ctx->press_det = TP_EVENT_PRESS_NOT_DET;
|
||
|
}
|
||
|
|
||
|
return TP_OK;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ft5xx6_read_gesture( ft5xx6_t * ctx )
|
||
|
{
|
||
|
uint8_t read_data;
|
||
|
|
||
|
read_data = ft5xx6_generic_read_single( ctx, FT5XX6_REG_GEST_ID );
|
||
|
|
||
|
for ( uint8_t idx = 0; idx < FT5XX6_GESTURE_ITEMS_MAX; idx++ )
|
||
|
{
|
||
|
if ( read_data == ctx->controller->gest_items[ idx ].key )
|
||
|
{
|
||
|
ctx->gesture = ctx->controller->gest_items[ idx ].value;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ------------------------------------------------------------------------ END
|