Это руководство написано на основе платы разработки DShanMCU-RA6M5, созданной Wei Dongshan Baiwen.com . Студенты, которым оно нужно, могут получить его здесь: https://item.taobao.com/item.htm?id=728461040949 .
Получите вспомогательную информацию: https://renesas-docs.100ask.net .
Краткое изложение руководств Renesas MCU с нулевой базой : https://blog.csdn.net/qq_35181236/article/details/132779862
Глава 15. Общий модуль шины I2C
Цели этой главы
- Используйте RASC для быстрой настройки модулей Common I2C.
- Научитесь использовать i2c API для управления сенсорными чипами и получения контактных данных.
15.1 Использование модуля Common I2C
I2C чипа RA разделен на простой I2C и общий I2C. Простой I2C — это режим I2C модуля SCI, упомянутый в главе 8 SCI SPI этой книги. Он использует последовательную шину для имитации протокола I2C, а общий I2C, упомянутый в этой главе, представляет собой аппаратный модуль контроллера I2C, который действительно существует. внутри чипа...
Благодаря инкапсуляции FSP нет большой разницы в применении между Simple I2C и Common I2C.
15.1.1 Конфигурация модуля I2C
Чтобы настроить модуль I2C, сначала найдите «Подключение: IIC» в «Периферийные устройства» в «Конфигурация контактов» RASC, а затем выберите канал I2C в соответствии с конструкцией оборудования. Например, в этой книге в качестве SDA и SCL I2C используются P409/P410. Эти два ввода-вывода принадлежат к контактам группы A I2C2, поэтому выберите «IIC2», а затем выберите «Выбор группы контактов» в расширенной конфигурации контактов. » и включите рабочий режим, как показано на рисунке ниже:
Затем перейдите в «Стеки», чтобы добавить модуль I2C. Нажмите «Новый стек», выберите «Подключение», а затем внутри выберите «I2C Master(r_iic_master)». Цель этой главы — служить хостом для чтения данных сенсорного экрана, поэтому выберите «Мастер», как показано на рисунке ниже:
После добавления модуля I2C Master необходимо настроить его параметры. Эксперименты в этой главе настраивают параметры I2C в RASC, как показано на рисунке ниже:
- Имя: имя модуля I2C, которое должно соответствовать стандарту строк языка C;
- Канал: канал модуля I2C;
- Скорость: скорость связи I2C, максимальная скорость, поддерживаемая в стандартном режиме, составляет 400 кбит/с, а максимальная скорость, поддерживаемая в быстром режиме, — 1 Мбит/с;
- Время нарастания/спада: время, необходимое для нарастания и спада сигнала SCL;
- Рабочий цикл: рабочий цикл линии синхронизации SCL, диапазон составляет 4–96 %, значение по умолчанию – 50 %;
- Адрес подчиненного устройства: адрес подчиненного устройства, установленный в соответствии с подчиненным чипом;
- Режим адреса: Режим адреса, поддерживает 7-битный и 10-битный;
- Режим тайм-аута: режим тайм-аута обнаружения данных, поддерживает длинный и короткий режимы. Счетчик тайм-аута в длинном режиме составляет 16 бит, а счетчик тайм-аута в коротком режиме — 14 бит; когда счетчик тайм-аута переполняется и данные не обнаруживаются, связь прекращается;
- Тайм-аут при низком уровне вероятности нежелательной почты: включить ли обнаружение тайм-аута при низком уровне вероятности нежелательной почты (по умолчанию включено);
- Обратный вызов: имя функции обратного вызова прерывания, рекомендуется совпадать с каналом, например i2c1_callback;
- Уровень приоритета прерывания: уровень приоритета прерывания I2C;
15.1.2 Интерпретация информации о конфигурации
Информация о конфигурации разделена на две части: информация о конфигурации контактов и информация о конфигурации модуля I2C.
После использования RASC для настройки параметров и создания проекта информация о выводах модуля будет сгенерирована в pin_data.c проекта, а информация о конфигурации модуля будет сгенерирована в hal_data.c.
- Информация о контактах модуля I2C
Пины участвуют в I2C, информация об их конфигурации генерируется в pin_data.c проекта. Каждый контакт, настроенный в RASC, будет генерировать элемент массива ioport_pin_cfg_t в pin_data.c, а содержимое внутри соответствует параметрам, выбранным во время настройки. код показан ниже:
const ioport_pin_cfg_t g_bsp_pin_cfg_data[] = {
......(省略内容)
{
.pin = BSP_IO_PORT_04_PIN_09,
.pin_cfg = ((uint32_t) IOPORT_CFG_DRIVE_MID
| (uint32_t) IOPORT_CFG_PERIPHERAL_PIN
| (uint32_t) IOPORT_PERIPHERAL_IIC)},
{
.pin = BSP_IO_PORT_04_PIN_10,
.pin_cfg = ((uint32_t) IOPORT_CFG_DRIVE_MID
| (uint32_t) IOPORT_CFG_PERIPHERAL_PIN
| (uint32_t) IOPORT_PERIPHERAL_IIC)},
......(省略内容)
};
Этот постоянный массив настраивает P5409 и P410 как функции мультиплексирования периферийных устройств I2C.
- Информация о конфигурации модуля I2C
Информация о конфигурации I2C будет определена в константе типа структуры i2c_master_cfg_t g_i2c_master2_cfg в файле hal_data.c. Код выглядит следующим образом:
const i2c_master_cfg_t g_i2c_master2_cfg =
{
.channel = 2,
.rate = I2C_MASTER_RATE_STANDARD,
.slave = 0x14,
.addr_mode = I2C_MASTER_ADDR_MODE_7BIT,
......(省略内容)
.p_callback = i2c2_callback,
.p_context = NULL,
......(省略内容)
.ipl = (12),
.p_extend = &g_i2c_master2_extend,
};
- Строка 03: Канал установлен на 2;
- Строка 04: Скорость связи установлена на стандартную скорость;
- Строка 05: Адрес подчиненного устройства — 0x14;
- Строка 06: Режим адреса — 7-битный;
- Строка 08: установите имя функции прерывания на i2c2_callback;
При использовании функции открытия I2C эта константа будет использоваться для инициализации модуля I2C.
15.1.3 Функция обратного вызова прерывания
Функция с именем "i2c1_callback" используется в g_i2c_master2_cfg. Эта функция объявлена только следующим образом в hal_data.h, но не реализована:
#ifndef i2c1_callback
void i2c1_callback(i2c_master_callback_args_t * p_args);
#endif
Пользователям необходимо реализовать эту функцию, например:
void i2c1_callback(i2c_master_callback_args_t * p_args)
{
switch (p_args->event)
{
}
}
Параметром этой функции обратного вызова прерывания является указатель на структуру i2c_master_callback_args_t. Прототип этой структуры следующий:
typedef struct st_i2c_master_callback_args
{
void const * p_context; ///< Pointer to user-provided context
i2c_master_event_t event; ///< Event code
} i2c_master_callback_args_t;
Член события представляет собой тип перечисления, включающий следующие типы событий:
typedef enum e_i2c_master_event
{
I2C_MASTER_EVENT_ABORTED = 1, ///< A transfer was aborted
I2C_MASTER_EVENT_RX_COMPLETE = 2, ///< A receive operation was completed successfully
I2C_MASTER_EVENT_TX_COMPLETE = 3 ///< A transmit operation was completed successfully
} i2c_master_event_t;
Отсюда мы можем узнать, что причинами срабатывания прерываний I2C являются: завершение передачи, завершение приема и прерывание передачи. После того, как они вызывают прерывание, вызывается функция обратного вызова для выполнения кода пользователя.
15.1.4 Интерфейс API и его применение
В заголовочном файле функции библиотеки FSP r_i2c_master_api.h модуля I2C определена структура операционной функции i2c_master_api_t хост-устройства I2C. Прототип выглядит следующим образом:
/** Interface definition for I2C access as master */
typedef struct st_i2c_master_api
{
fsp_err_t (* open)(i2c_master_ctrl_t * const p_ctrl,
i2c_master_cfg_t const * const p_cfg);
fsp_err_t (* read)(i2c_master_ctrl_t * const p_ctrl,
uint8_t * const p_dest,
uint32_t const bytes,
bool const restart);
fsp_err_t (* write)(i2c_master_ctrl_t * const p_ctrl,
uint8_t * const p_src,
uint32_t const bytes,
bool const restart);
fsp_err_t (* abort)(i2c_master_ctrl_t * const p_ctrl);
fsp_err_t (* slaveAddressSet)(i2c_master_ctrl_t * const p_ctrl,
uint32_t const slave,
i2c_master_addr_mode_t const addr_mode);
fsp_err_t (* callbackSet)(i2c_master_ctrl_t * const p_api_ctrl,
void (* p_callback)(i2c_master_callback_args_t *),
void const * const p_context,
i2c_master_callback_args_t * const p_callback_memory);
fsp_err_t (* statusGet)(i2c_master_ctrl_t * const p_api_ctrl,
i2c_master_status_t * p_status);
fsp_err_t (* close)(i2c_master_ctrl_t * const p_ctrl);
} i2c_master_api_t;
Операции, поддерживаемые хост-устройством I2C: открытие/чтение/запись/закрытие и т. д. FSP реализует эту структуру в r_iic_master.c:
/* IIC Implementation of I2C device master interface */
i2c_master_api_t const g_i2c_master_on_iic =
{
.open = R_IIC_MASTER_Open,
.read = R_IIC_MASTER_Read,
.write = R_IIC_MASTER_Write,
.abort = R_IIC_MASTER_Abort,
.slaveAddressSet = R_IIC_MASTER_SlaveAddressSet,
.close = R_IIC_MASTER_Close,
.statusGet = R_IIC_MASTER_StatusGet,
.callbackSet = R_IIC_MASTER_CallbackSet
};
В этой главе в качестве примера для анализа рассматриваются открытие, закрытие, чтение и запись хост-устройства I2C.
- Включите главное устройство I2C.
Прототип указателя функции для открытия хост-устройства I2C выглядит следующим образом:
/** Opens the I2C Master driver and initializes the hardware.
* @param[in] p_ctrl Pointer to control block. Must be declared by user. Elements are set here.
* @param[in] p_cfg Pointer to configuration structure.
*/
fsp_err_t (* open)(i2c_master_ctrl_t * const p_ctrl, i2c_master_cfg_t const * const p_cfg);
- p_ctrl: указывает на блок управления хостом I2C, например g_i2c_master2_ctrl;
- p_cfg: указывает на константу структуры конфигурации параметров хоста I2C, например g_i2c_master2_cfg;
Типом p_ctrl является структура iic_master_instance_ctrl_t. Во время связи I2C в этой структуре будет изменен статус устройства, значение адреса, статус чтения и записи, статус ответа и т. д.
Тип p_cfg — i2c_master_cfg_t. Эта структура используется для представления конфигурации хоста I2C, такой как каналы I2C, номера прерываний, функции приемопередатчика и функции обратного вызова прерываний.
Пользователи могут обратиться к следующему коду, чтобы открыть хост-устройство I2C, которое будет инициализировано внутри:
fsp_err_t err = g_i2c_master2.p_api->open(g_i2c_master2.p_ctrl, g_i2c_master2.p_cfg);
if (FSP_SUCCESS != err)
{
printf("%s %d\r\n", __FUNCTION__, __LINE__);
return;
}
- Выключите хост-устройство I2C.
Прототип указателя функции для закрытия устройства I2C выглядит следующим образом:
fsp_err_t (* close)(i2c_master_ctrl_t * const p_ctrl);
Ее параметр p_ctrl указывает на блок управления хостом I2C. Эта функция изменит состояние I2C в блоке управления на выключенное состояние.
- I2C функция получения данных
Прототип указателя функции приема данных I2C выглядит следующим образом:
fsp_err_t (* read)(i2c_master_ctrl_t * const p_ctrl,
uint8_t * const p_dest,
uint32_t const bytes,
bool const restart);
- p_ctrl: указывает на блок управления хост-устройством I2C;
- p_dest: адрес данных назначения (используется для получения данных);
- байты: количество данных, которые необходимо получить, единица измерения — байты;
- перезапуск: операция после получения хостом кадра данных, true — после получения кадра данных хост не отправляет сигнал остановки, а отправляет сигнал Start для продолжения передачи, false — после получения кадра данных хост подает сигнал остановки.
Разработчики могут обратиться к следующему коду для чтения данных:
fsp_err_t err = g_i2c_master2.p_api->read(g_i2c_master2.p_ctrl, buf, len, 0);
if (FSP_SUCCESS != err)
{
printf("%s %d\r\n", __FUNCTION__, __LINE__);
return;
}
- Функция отправки данных I2C
Прототип указателя функции для ведущего устройства I2C для отправки данных на ведомое устройство выглядит следующим образом:
fsp_err_t (* write)(i2c_master_ctrl_t * const p_ctrl,
uint8_t * const p_src,
uint32_t const bytes,
bool const restart);
- p_ctrl: выполнить блок управления хост-устройством I2C. Когда хост отправляет данные, он инициирует сигналы запуска, сигналы ответа и т. д. на основе адреса и другой информации блока управления;
- p_dest: адрес данных назначения (используется для получения данных);
- байты: количество отправляемых данных в байтах;
- перезапуск: операция после отправки этого кадра данных: true означает, что сигнал Stop не будет отправлен, но сигнал Start будет отправлен немедленно - это всегда может занять шину I2C, false означает, что сигнал Stop будет отправлен (все будут отправлены). снова побороться за шину I2C);
Разработчики могут обратиться к следующему коду для отправки данных I2C:
fsp_err_t err = g_i2c_master2.p_api->write(g_i2c_master2.p_ctrl, tmpbuf, 2, 0);
if (FSP_SUCCESS != err)
{
printf("%s %d\r\n", __FUNCTION__, __LINE__);
return;
}
15.2 Общий эксперимент с сенсорным экраном драйвера I2C
15.2.1 Подключение оборудования
В этой главе используется внешний сенсорный экран, который подключается к материнской плате с помощью кабеля FPC. Принципиальная схема I2C FPC показана ниже:
Используются контакты P409 и P410.
15.2.2 Анализ драйвера GT911
GT911 - это сенсорный чип с емкостными точками касания 5, каналами привода 26 и каналами восприятия 14. Он может одновременно определять точное положение, траекторию движения и область касания в режиме реального времени в пяти точках касания, а также в соответствии с основными управление При необходимости прочтите сенсорную информацию соответствующей точки.
Связь GT911 представляет собой стандартный протокол связи I2C, и хост должен соответствовать стандартному протоколу шины I2C, когда он взаимодействует с GT911 через I2C. Определение адреса ведомого устройства I2C GT911 показано на рисунке ниже:
Он поддерживает два адреса, какой адрес используется, зависит от уровня вывода INT после сброса GT911. Если во время сброса на выводе INT высокий уровень, адрес равен 0x14/0x28/0x29; в противном случае это 0x5D, 0xBA/0xBB.
В экспериментальной схеме в этой главе был выбран адрес 0x14.
GT911 управляется отправкой инструкций, а также чтением и записью данных.Разные инструкции поддерживают разное количество данных: одна инструкция соответствует данным одного регистра, или одна инструкция может соответствовать данным N регистров. Взяв в качестве примера команду чтения данных точки 0x8157, пользователь может непрерывно считывать 7 байтов данных (идентификатор точки касания и информацию о положении касания) после отправки команды 0x8157:
15.2.3 Драйвер GT911
Эксперимент в этой главе просто получает информацию о положении контакта. Для сенсорных устройств, поскольку основным требованием является получение информации о точках касания, эта глава будет абстрагироваться как «сенсорные устройства» и использовать структуру в drv_touch.h для описания этого типа сенсорного устройства:
typedef struct TouchDev{
char *name;
void (*Init)(struct TouchDev *ptDev);
bool (*Read)(struct TouchDev *ptDev, unsigned short *pX, unsigned short *pY);
}TouchDev, *PTouchDev;
Для этого типа сенсорного устройства операции прикладного уровня включают только: инициализацию и считывание положения касания. Поэтому в структуре TouchDev имеется только два указателя на функции: Init и Read.
Для конкретных чипов сенсорного драйвера необходимо реализовать собственную структуру TouchDev. В этой главе реализуется структура TouchDev в drv_gt911.c, а затем последовательно объясняются ее функции.
- функция обратного вызова прерывания
Во время процесса связи I2C следующая передача должна быть завершена после завершения предыдущей передачи.Поэтому необходимо определить, была ли предыдущая передача завершена с помощью события запуска прерывания I2C.Код выглядит следующим образом:
static volatile bool gI2C2TxCplt = false;
static volatile bool gI2C2RxCplt = false;
void i2c2_callback(i2c_master_callback_args_t * p_args)
{
switch (p_args->event)
{
case I2C_MASTER_EVENT_TX_COMPLETE:
{
gI2C2TxCplt = true;
break;
}
case I2C_MASTER_EVENT_RX_COMPLETE:
{
gI2C2RxCplt = true;
break;
}
default:
{
gI2C2TxCplt = gI2C2RxCplt = false;
break;
}
}
}
- Строки 07–11: Если тип события, вызывающего прерывание, является событием завершения отправки, флаг завершения отправки будет установлен в значение true;
- Строки 12–16: Если тип события, вызывающего прерывание, является событием завершения приема, флаг завершения приема будет установлен в значение true;
- Функция ожидания тайм-аута трансивера
В этой главе реализованы две функции ожидания и добавлен механизм таймаута.Код выглядит следующим образом:
static void I2C2WaitTxCplt(void)
{
uint16_t wTimeOut = 100;
while(!gI2C2TxCplt && wTimeOut)
{
HAL_Delay(1);
wTimeOut--;
}
gI2C2TxCplt = false;
}
static void I2C2WaitRxCplt(void)
{
uint16_t wTimeOut = 100;
while(!gI2C2RxCplt && wTimeOut)
{
HAL_Delay(1);
wTimeOut--;
}
gI2C2RxCplt = false;
}
- Запись функции регистра GT911
При записи регистра GT911 необходимо отправить адрес регистра и данные регистра. Количество данных может варьироваться.Функция динамически выделяет память для сохранения адреса регистра и данных регистра, а затем отправляет их одновременно. Обратитесь к следующему коду:
static void GT911DrvWriteReg(uint16_t reg, uint8_t *buf, uint8_t len)
{
uint8_t regl = (uint8_t)(reg & 0xff);
uint8_t regh = (uint8_t)(reg>>8);
uint8_t * write_package = (uint8_t*)malloc((len + 2) * sizeof(uint8_t));
memcpy(write_package, ®h, 1);
memcpy(write_package + 1, ®l, 1);
memcpy(write_package + 2, buf, len);
fsp_err_t err = g_i2c_master2.p_api->write(g_i2c_master2.p_ctrl, write_package, len + 2, 0);
if (FSP_SUCCESS != err)
{
printf("%s %d\r\n", __FUNCTION__, __LINE__);
return;
}
I2C2WaitTxCplt();
free(write_package);
}
- Строки 05–08: динамически распределять пакеты данных в соответствии с длиной входящих данных и упаковывать инструкции и данные так, чтобы их можно было отправить сразу, вызывая функцию записи I2C;
- Строка 09: вызов функции записи для отправки пакета данных.После отправки данные больше не будут отправляться, поэтому последний параметр restart=0;
- Чтение функции регистра GT911
При чтении регистра сначала должен быть отправлен адрес регистра, а затем должны быть считаны данные. код показан ниже:
static void GT911DrvReadReg(uint16_t reg, uint8_t *buf, uint8_t len)
{
uint8_t tmpbuf[2];
tmpbuf[0] = (uint8_t)(reg >> 8);
tmpbuf[1] = (uint8_t)(reg &0xff);
fsp_err_t err = g_i2c_master2.p_api->write(g_i2c_master2.p_ctrl, tmpbuf, 2, 0);
if (FSP_SUCCESS != err)
{
printf("%s %d\r\n", __FUNCTION__, __LINE__);
return;
}
I2C2WaitTxCplt();
err = g_i2c_master2.p_api->read(g_i2c_master2.p_ctrl, buf, len, 0);
if (FSP_SUCCESS != err)
{
printf("%s %d\r\n", __FUNCTION__, __LINE__);
return;
}
I2C2WaitRxCplt();
}
- Различные функции считывания идентификатора
GT911 имеет множество идентификаторов, которые могут получить пользователи. Если взять в качестве примера производственный идентификатор GT911, он требует, чтобы хост отправил команду регистрации 0x8140 в GT911, а затем прочитал 4 байта идентификационных данных. Код выглядит следующим образом:
static uint32_t GT911DrvReadProductID(void)
{
uint32_t id = 0;
GT911DrvReadReg(GT911_PRODUCT_ID_REG, (uint8_t*)&id ,4);
return id;
}
Другие идентификаторы также можно реализовать, обратившись к этому методу записи.Проект 1501_i2c_touch в этой главе инкапсулирует эти функции чтения идентификаторов для читателей:
static uint32_t GT911DrvReadProductID(void);
static uint32_t GT911DrvReadVendorID(void);
static uint8_t GT911DrvReadVersion(void);
static uint8_t GT911DrvGetGSTID(void);
- Очистить регистр точек
После каждого чтения данных регистра точки касания данные в регистре необходимо очистить, чтобы данные в регистре можно было обновить при следующем касании. Если данные в регистре координат не очищены, при каждом чтении будет получаться фиксированное значение 0x7F.
Адрес очистки регистра координат 0x814E.Пользователю необходимо только записать ноль в этот регистр.Код следующий:
static void GT911DrvClearBuf(void)
{
uint8_t data = {
0};
GT911DrvWriteReg(GT911_CLEARBUF_REG, (uint8_t*)&data, 1);
}
- Абстрактный объект устройства с сенсорным экраном GT911
Для сенсорного устройства GT911 эта глава инкапсулирована в соответствии с характеристиками его параметров для представления области касания и точек касания GT911. См. следующий дизайн кода в drv_gt911.h:
typedef enum{
TP_ROT_NONE = 0,
TP_ROT_90,
TP_ROT_180,
TP_ROT_270
} TouchRotation_t;
/**用于存放每一个触控点的id,坐标,大小**/
typedef struct TouchPointInfo{
unsigned char id;
unsigned short x;
unsigned short y;
unsigned short size;
}TouchPointInfo_t;
/**类结构体**/
typedef struct TouchDrv{
unsigned char ucAddr;
unsigned short wHeight;
unsigned short wWidth;
TouchRotation_t tRotation;
TouchPointInfo_t tPointsInfo[TOUCH_POINT_TOTAL]; //用于存储五个触控点的坐标
}TouchDrv_t;
В последующем проекте устройство GT911 представлено определением структурной переменной TouchDrv_t:
static struct TouchDrv gTP;
- Прочитайте функцию точки касания GT911
Анализируя чтение и запись данных GT911, я использовал в качестве примера чтение данных определенной точки и узнал, что одна точка имеет 7 данных данных. Для GT911 можно получить информацию по 5 точкам, а соответствующий адрес регистра отражается в форме определения макроса в drv_gt911.h:
#define GT_TP1_REG 0X814F //第一个触摸点数据地址
#define GT_TP2_REG 0X8157 //第二个触摸点数据地址
#define GT_TP3_REG 0X815F //第三个触摸点数据地址
#define GT_TP4_REG 0X8167 //第四个触摸点数据地址
#define GT_TP5_REG 0X816F //第五个触摸点数据地址
При каких обстоятельствах нам необходимо считывать информацию о точках? Когда происходит событие касания. А как пользователи узнают, трогали ли GT911? Он представлен регистром:
- Бит-7:buffer_status, 1 — есть сенсорные данные, ожидающие чтения хостом, 0 — данных нет;
- Бит-6: большое обнаружение, 1- означает, что затронута большая площадь;
- Бит-4:HaveKey,1-прикоснулись, 0-не прикоснулись или отпустили касание;
- Бит-[3:0]: количество точек касания;
Пользователь может получить информацию о точках каждого касания в соответствии с 6 инструкциями по регистрации, см. следующий код:
static bool GT911DrvIsTouched(TouchDrv_t * tp)
{
uint8_t touched_state, touch_num, buffer_status;
touched_state = GT911DrvGetGSTID();
touch_num = touched_state & 0xf; //触点数量
buffer_status = (touched_state >> 7) & 1; // 帧状态
if(buffer_status == 1 && (touch_num <= TOUCH_POINT_TOTAL) && (touch_num > 0))
{
uint16_t pointers_regs[TOUCH_POINT_TOTAL] = {
GT_TP1_REG, GT_TP2_REG, GT_TP3_REG, GT_TP4_REG, GT_TP5_REG};
// 获取每个触控点的坐标值并保存
for (int i = 0; i < touch_num; ++i)
{
uint8_t point_info_per_size = 7;
uint8_t * point_info_p = malloc(point_info_per_size * sizeof(uint8_t ));
GT911DrvReadReg(pointers_regs[i], point_info_p, point_info_per_size);
tp->tPointsInfo[i].id = point_info_p[0];
tp->tPointsInfo[i].x = (unsigned short)(point_info_p[1] + (point_info_p[2] << 8));
tp->tPointsInfo[i].y = (unsigned short)(point_info_p[3] + (point_info_p[4] << 8));
tp->tPointsInfo[i].size = (unsigned short)(point_info_p[5] + (point_info_p[6] << 8));
free(point_info_p);
//旋转方向
uint16_t temp;
switch (tp->tRotation)
{
case TP_ROT_NONE:
tp->tPointsInfo[i].x = tp->wWidth - tp->tPointsInfo[i].x;
tp->tPointsInfo[i].y = tp->wHeight - tp->tPointsInfo[i].y;
break;
case TP_ROT_270:
temp = tp->tPointsInfo[i].x;
tp->tPointsInfo[i].x = tp->wWidth - tp->tPointsInfo[i].y;
tp->tPointsInfo[i].y = temp;
break;
case TP_ROT_180:
// tp->tPointsInfo[i].x = tp->tPointsInfo[i].x;
// tp->tPointsInfo[i].y = tp->tPointsInfo[i].y;
break;
case TP_ROT_90:
temp = tp->tPointsInfo[i].x;
tp->tPointsInfo[i].x = tp->tPointsInfo[i].y;
tp->tPointsInfo[i].y = tp->wHeight - temp;
break;
default:
break;
}
}
GT911DrvClearBuf();
return true;
}
//必须给GT911_POINT_INFO缓冲区置0,不然读取的数据一直为128!!!!
GT911DrvClearBuf();
return false;
}
Кроме того, чтобы соответствовать ранее абстрактному сенсорному устройству (TouchDev), функция чтения должна быть инкапсулирована на этой основе:
static bool GT911DrvRead(struct TouchDev *ptDev, unsigned short *pX, unsigned short *pY)
{
if(NULL == ptDev->name) return false;
if(GT911DrvIsTouched(&gTP))
{
*pX = gTP.tPointsInfo[0].x;
*pY = gTP.tPointsInfo[0].y;
return true;
}
return false;
}
- Функция инициализации GT911
Эксперименты в этой главе не привели к более тонким настройкам GT911, поэтому его регистры не были изменены.
Функция инициализации в этой главе только инициализирует устройство I2C и считывает идентификатор и диапазон касания GT911. См. следующий код:
static void GT911DrvInit(struct TouchDev *ptDev)
{
if(NULL == ptDev->name) return;
uint8_t buf[4];
gTP.ucAddr = (uint8_t)g_i2c_master2.p_cfg->slave;
gTP.tRotation = TP_ROT_NONE;
/* 初始化I2C驱动 */
fsp_err_t err = g_i2c_master2.p_api->open(g_i2c_master2.p_ctrl, g_i2c_master2.p_cfg);
if (FSP_SUCCESS != err)
{
printf("%s %d\r\n", __FUNCTION__, __LINE__);
return;
}
/* 读ID */
uint32_t nVendorID = GT911DrvReadVendorID();
printf("gt911 vendor id: 0x%.4x\r\n", (int)nVendorID);
uint32_t nProductID = GT911DrvReadProductID();
printf("gt911 product id: 0x%.4x\r\n", (int)nProductID);
uint8_t nVersion = GT911DrvReadVersion();
printf("version = 0x%x\r\n", nVersion);
GT911DrvReadReg(0x8048, buf, 2);
gTP.wWidth = (unsigned short)((buf[1] << 8) | buf[0]);
GT911DrvReadReg(0x804A, buf, 2);
gTP.wHeight = (unsigned short)((buf[1] << 8) | buf[0]);
}
- Регистрация и приобретение сенсорных устройств
При объектно-ориентированном мышлении создается структура TouchDev gTouchDev, код следующий:
static struct TouchDev gTouchDev = {
.name = "GT911",
.Init = GT911DrvInit,
.Read = GT911DrvRead
};
Затем верните это устройство в верхнее приложение с помощью функции:
struct TouchDev* TouchDevGet(void)
{
return &gTouchDev;
}
15.2.4 Процедура испытания
app_test.c — тестовая программа, она распечатывает информацию о точках касания, код следующий:
void TouchAppTest(void)
{
TouchDev *ptDev = TouchDevGet();
if(NULL == ptDev)
{
printf("Error. Not Found Touch Device!\r\n");
return;
}
ptDev->Init(ptDev);
uint16_t x = 0, y = 0;
while(1)
{
if(ptDev->Read(ptDev, &x, &y) == true)
{
printf("Touch-Position: (%d,%d)\r\n", x, y);
}
}
}
15.2.5 Компьютерный эксперимент
В функции hal_entry() в hal_entry.c инициализируйте тактовый таймер, инициализируйте последовательный порт отладки, а затем вызовите функцию TouchAppTest для тестирования.
При прикосновении к экрану помощник последовательного порта распечатает информацию о координатах точки, как показано на следующем рисунке: