//****************************************************************************** /// \brief Disable noise suppression objects static void disable_noise_suppression(struct mxt_device *mxt) { uint16_t addr; uint8_t disable = 0; addr = mxt_get_object_address(mxt, PROCG_NOISESUPPRESSION_T22, 0); if (addr != OBJECT_NOT_FOUND) { mxt_write_register(mxt, &disable, addr, 1); } addr = mxt_get_object_address(mxt, PROCG_NOISESUPPRESSION_T48, 0); if (addr != OBJECT_NOT_FOUND) { mxt_write_register(mxt, &disable, addr, 1); } addr = mxt_get_object_address(mxt, PROCG_NOISESUPPRESSION_T54, 0); if (addr != OBJECT_NOT_FOUND) { mxt_write_register(mxt, &disable, addr, 1); } addr = mxt_get_object_address(mxt, PROCG_NOISESUPPRESSION_T62, 0); if (addr != OBJECT_NOT_FOUND) { mxt_write_register(mxt, &disable, addr, 1); } }
//****************************************************************************** /// \brief Retrieve and store object information for debug data operation /// \return #mxt_rc static int get_objects_addr(struct t37_ctx *ctx) { int t6_addr; /* Obtain command processor's address */ t6_addr = mxt_get_object_address(ctx->mxt, GEN_COMMANDPROCESSOR_T6, 0); if (t6_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; /* T37 commands address */ ctx->diag_cmd_addr = t6_addr + MXT_T6_DIAGNOSTIC_OFFSET; /* Obtain Debug Diagnostic object's address */ ctx->t37_addr = mxt_get_object_address(ctx->mxt, DEBUG_DIAGNOSTIC_T37, 0); if (ctx->t37_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; /* Obtain Debug Diagnostic object's size */ ctx->t37_size = mxt_get_object_size(ctx->mxt, DEBUG_DIAGNOSTIC_T37); if (ctx->t37_size == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; ctx->t111_instances = mxt_get_object_instances(ctx->mxt, SPT_SELFCAPCONFIG_T111); ctx->t107_instances = mxt_get_object_instances(ctx->mxt, PROCI_ACTIVESTYLUS_T107); return MXT_SUCCESS; }
//****************************************************************************** /// \brief Get next MSG into byte buffer /// \return #mxt_rc int t44_get_msg_bytes(struct mxt_device *mxt, unsigned char *buf, size_t buflen, int *count) { int ret; uint16_t addr; uint16_t size; addr = mxt_get_object_address(mxt, GEN_MESSAGEPROCESSOR_T5, 0); if (addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; /* Do not read CRC byte */ size = mxt_get_object_size(mxt, GEN_MESSAGEPROCESSOR_T5) - 1; if (size > buflen) { mxt_err(mxt->ctx, "Buffer too small!"); return MXT_ERROR_NO_MEM; } ret = mxt_read_register(mxt, buf, addr, size); if (ret) return ret; /* Check for invalid message */ if (buf[0] == 255u) { mxt_verb(mxt->ctx, "Invalid message"); return MXT_ERROR_NO_MESSAGE; } *count = size; return MXT_SUCCESS; }
//****************************************************************************** /// \brief Check chip is not in deep sleep /// \return #mxt_rc static int mxt_t68_check_power_cfg(struct t68_ctx *ctx) { uint16_t t7_addr; uint8_t buf[2]; int ret; /* Skip if object not present */ t7_addr = mxt_get_object_address(ctx->mxt, GEN_POWERCONFIG_T7, 0); if (t7_addr == OBJECT_NOT_FOUND) return MXT_SUCCESS; ret = mxt_read_register(ctx->mxt, &buf[0], t7_addr, sizeof(buf)); if (ret) return ret; mxt_verb(ctx->lc, "T7 IDLEACQINT=%u ACTVACQINT=%u", buf[0], buf[1]); if ((buf[0] == 0) || (buf[1] == 0)) { mxt_err(ctx->lc, "Warning: The T7 power configuration object shows that the chip " "is in deep sleep, and so will not process T68 serial data " "commands. Please set the T7 power configuration idle acquisition " "interval to a non-zero value and try again."); return MXT_ERROR_UNEXPECTED_DEVICE_STATE; } else { return MXT_SUCCESS; } }
//****************************************************************************** /// \brief Perform fallback reset /// \return #mxt_rc static int mxt_send_reset_command(struct mxt_device *mxt, bool bootloader_mode) { int ret; uint16_t t6_addr; unsigned char write_value = RESET_COMMAND; /* Obtain command processor's address */ t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0); if (t6_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; /* The value written determines which mode the chip will boot into */ if (bootloader_mode) { mxt_info(mxt->ctx, "Resetting in bootloader mode"); write_value = BOOTLOADER_COMMAND; } else { mxt_info(mxt->ctx, "Sending reset command"); } /* Write to command processor register to perform command */ ret = mxt_write_register ( mxt, &write_value, t6_addr + MXT_T6_RESET_OFFSET, 1 ); return ret; }
//****************************************************************************** /// \brief Get number of messages /// \return #mxt_rc int t44_get_msg_count(struct mxt_device *mxt, int *count_out) { uint16_t addr; int ret; uint8_t count; addr = mxt_get_object_address(mxt, SPT_MESSAGECOUNT_T44, 0); if (addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; /* Get T44 count */ ret = mxt_read_register(mxt, &count, addr, 1); if (ret) return ret; *count_out = count; return MXT_SUCCESS; }
//****************************************************************************** /// \brief Run self test int run_self_tests(struct mxt_device *mxt, uint8_t cmd) { uint16_t t25_addr; uint8_t enable = 3; mxt_msg_reset(mxt); // Enable self test object & reporting t25_addr = mxt_get_object_address(mxt, SPT_SELFTEST_T25, 0); mxt_info(mxt->ctx, "Enabling self test object"); mxt_write_register(mxt, &enable, t25_addr, 1); mxt_info(mxt->ctx, "Disabling noise suppression"); disable_noise_suppression(mxt); print_t25_limits(mxt, t25_addr); mxt_info(mxt->ctx, "Running tests"); mxt_write_register(mxt, &cmd, t25_addr + 1, 1); return self_test_handle_messages(mxt); }
//****************************************************************************** /// \brief Backup configuration settings to non-volatile memory /// \return #mxt_rc int mxt_backup_config(struct mxt_device *mxt, uint8_t backup_command) { int ret; uint16_t t6_addr; /* Obtain command processor's address */ t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0); if (t6_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; /* Write to command processor register to perform command */ ret = mxt_write_register ( mxt, &backup_command, t6_addr + MXT_T6_BACKUPNV_OFFSET, 1 ); if (ret == MXT_SUCCESS) mxt_info(mxt->ctx, "Backed up settings to the non-volatile memory"); else mxt_err(mxt->ctx, "Failed to back up settings"); return ret; }
//****************************************************************************** /// \brief Issue REPORTALL command to device /// \return #mxt_rc int mxt_report_all(struct mxt_device *mxt) { int ret; uint16_t t6_addr; const uint8_t report_all_cmd = 0xff; /* Obtain command processor's address */ t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0); if (t6_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; /* Write to command processor register to perform command */ ret = mxt_write_register ( mxt, &report_all_cmd, t6_addr + MXT_T6_REPORTALL_OFFSET, 1 ); if (ret == MXT_SUCCESS) mxt_info(mxt->ctx, "REPORTALL command issued"); else mxt_err(mxt->ctx, "Failed to issue REPORTALL command"); return ret; }
//****************************************************************************** /// \brief Calibrate maxtouch chip /// \return 0 = success, negative = fail int mxt_calibrate_chip(struct mxt_device *mxt) { int ret; uint16_t t6_addr; unsigned char write_value = CALIBRATE_COMMAND; /* Obtain command processor's address */ t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0); if (t6_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; mxt_flush_msgs(mxt); /* Write to command processor register to perform command */ ret = mxt_write_register(mxt, &write_value, t6_addr + MXT_T6_CALIBRATE_OFFSET, 1); if (ret == 0) { mxt_info(mxt->ctx, "Sent calibration command"); } else { mxt_err(mxt->ctx, "Failed to send calibration command"); } int state = 0; int flag = false; ret = mxt_read_messages(mxt, MXT_CALIBRATE_TIMEOUT, &state, handle_calibrate_msg, &flag); if (ret == MXT_ERROR_TIMEOUT) { mxt_warn(mxt->ctx, "WARN: timed out waiting for calibrate status"); return MXT_SUCCESS; } else if (ret) { mxt_err(mxt->ctx, "FAIL: device calibration failed"); return ret; } return MXT_SUCCESS; }
/** * \brief Set maXTouch configuration * * This function writes a set of predefined, optimal maXTouch configuration data * to the mXT143E Xplained. * * \param device Pointer to mxt_device struct */ static void mxt_init(struct mxt_device *device) { enum status_code status; UNUSED(status); /* T8 configuration object data */ uint8_t t8_object[] = { 0x10, 0x05, 0x0a, 0x14, 0x64, 0x00, 0x05, 0x0a, 0x00, 0x00, }; /* T9 configuration object data */ uint8_t t9_object[] = { 0x8f, 0x00, 0x00, 0x0d, 0x0b, 0x00, 0x21, 0x3c, 0x0f, 0x00, 0x32, 0x01, 0x01, 0x00, 0x08, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x1c, 0x37, 0x37, 0x8f, 0x50, 0xcf, 0x6e, 0x00, 0x02, 0x2f, 0x2c, 0x00 }; /* T48 configuration object data */ uint8_t t48_object[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* TWI configuration */ twi_master_options_t twi_opt = { .speed = MXT_TWI_SPEED, .chip = MAXTOUCH_TWI_ADDRESS, }; status = twi_master_setup(TWI_INTERFACE, &twi_opt); Assert(status == STATUS_OK); /* Initialize the maXTouch device */ status = mxt_init_device(device, TWI_INTERFACE, MAXTOUCH_TWI_ADDRESS, MXT143E_XPLAINED_CHG); Assert(status == STATUS_OK); /* Issue soft reset of maXTouch device by writing a non-zero value to * the reset register */ mxt_write_config_reg(device, mxt_get_object_address(device, MXT_GEN_COMMANDPROCESSOR_T6, 0) + MXT_GEN_COMMANDPROCESSOR_RESET, 0x01); /* Wait for the reset of the device to complete */ delay_ms(MXT_RESET_TIME); /* Write data to configuration registers in T7 configuration object */ mxt_write_config_reg(device, mxt_get_object_address(device, MXT_GEN_POWERCONFIG_T7, 0) + 0, 0xff); mxt_write_config_reg(device, mxt_get_object_address(device, MXT_GEN_POWERCONFIG_T7, 0) + 1, 0xff); mxt_write_config_reg(device, mxt_get_object_address(device, MXT_GEN_POWERCONFIG_T7, 0) + 2, 0x32); /* Write predefined configuration data to configuration objects */ mxt_write_config_object(device, mxt_get_object_address(device, MXT_GEN_ACQUISITIONCONFIG_T8, 0), &t8_object); mxt_write_config_object(device, mxt_get_object_address(device, MXT_TOUCH_MULTITOUCHSCREEN_T9, 0), &t9_object); mxt_write_config_object(device, mxt_get_object_address(device, MXT_PROCG_TOUCHSUPPRESSION_T48, 0), &t48_object); /* Issue recalibration command to maXTouch device by writing a non-zero * value to the calibrate register */ mxt_write_config_reg(device, mxt_get_object_address(device, MXT_GEN_COMMANDPROCESSOR_T6, 0) + MXT_GEN_COMMANDPROCESSOR_CALIBRATE, 0x01); }
//****************************************************************************** /// \brief Run self cap tuning procedure without updating the config /// checksum /// \return #mxt_rc int mxt_self_cap_tune(struct mxt_device *mxt, mxt_app_cmd cmd) { int ret; uint16_t t6_addr; uint16_t t109_addr; uint8_t backupnv_value; uint8_t t109_command; mxt_msg_reset(mxt); // Enable self test object & reporting t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0); if (t6_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; t109_addr = mxt_get_object_address(mxt, SPT_SELFCAPGLOBALCONFIG_T109, 0); if (t109_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; mxt_info(mxt->ctx, "Stopping T70"); backupnv_value = 0x33; ret = mxt_write_register(mxt, &backupnv_value, t6_addr + MXT_T6_BACKUPNV_OFFSET, 1); if (ret) return ret; // Wait for backup operation to complete (otherwise T109 report may be missed) mxt_msg_wait(mxt, 100); mxt_info(mxt->ctx, "Tuning"); t109_command = T109_CMD_TUNE; mxt_info(mxt->ctx, "Writing %u to T109 CMD register", cmd); ret = mxt_write_register(mxt, &t109_command, t109_addr + T109_CMD_OFFSET, 1); if (ret) return ret; ret = mxt_read_messages(mxt, T109_TIMEOUT, &t109_command, mxt_self_cap_command, (int *)&mxt_sigint_rx); if (ret) return ret; switch (cmd) { case CMD_SELF_CAP_TUNE_CONFIG: mxt_info(mxt->ctx, "Store to Config"); t109_command = T109_CMD_STORE_TO_CONFIG_RAM; break; default: case CMD_SELF_CAP_TUNE_NVRAM: mxt_info(mxt->ctx, "Store to NVRAM"); t109_command = T109_CMD_STORE_TO_NVM; break; } mxt_info(mxt->ctx, "Writing %u to T109 CMD register", cmd); ret = mxt_write_register(mxt, &t109_command, t109_addr + T109_CMD_OFFSET, 1); if (ret) return ret; ret = mxt_read_messages(mxt, 100, (void *) &t109_command, mxt_self_cap_command, (int *)&mxt_sigint_rx); if (ret) return ret; mxt_info(mxt->ctx, "Saving configuration"); ret = mxt_backup_config(mxt, BACKUPNV_COMMAND); if (ret) return ret; ret = mxt_reset_chip(mxt, false); if (ret) return ret; return MXT_SUCCESS; }
/** * \brief Set maXTouch configuration * * This function writes a set of predefined, optimal maXTouch configuration data * to the maXTouch Xplained Pro. * * \param device Pointer to mxt_device struct */ static void mxt_init(struct mxt_device *device) { enum status_code status; /* T8 configuration object data */ uint8_t t8_object[] = { 0x0d, 0x00, 0x05, 0x0a, 0x4b, 0x00, 0x00, 0x00, 0x32, 0x19 }; /* T9 configuration object data */ uint8_t t9_object[] = { 0x8B, 0x00, 0x00, 0x0E, 0x08, 0x00, 0x80, 0x32, 0x05, 0x02, 0x0A, 0x03, 0x03, 0x20, 0x02, 0x0F, 0x0F, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x02, 0x02 }; /* T46 configuration object data */ uint8_t t46_object[] = { 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00 }; /* T56 configuration object data */ uint8_t t56_object[] = { 0x02, 0x00, 0x01, 0x18, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* TWI configuration */ twihs_master_options_t twi_opt = { .speed = MXT_TWI_SPEED, .chip = MAXTOUCH_TWI_ADDRESS, }; status = (enum status_code)twihs_master_setup(MAXTOUCH_TWI_INTERFACE, &twi_opt); Assert(status == STATUS_OK); /* Initialize the maXTouch device */ status = mxt_init_device(device, MAXTOUCH_TWI_INTERFACE, MAXTOUCH_TWI_ADDRESS, MAXTOUCH_XPRO_CHG_PIO); Assert(status == STATUS_OK); /* Issue soft reset of maXTouch device by writing a non-zero value to * the reset register */ mxt_write_config_reg(device, mxt_get_object_address(device, MXT_GEN_COMMANDPROCESSOR_T6, 0) + MXT_GEN_COMMANDPROCESSOR_RESET, 0x01); /* Wait for the reset of the device to complete */ delay_ms(MXT_RESET_TIME); /* Write data to configuration registers in T7 configuration object */ mxt_write_config_reg(device, mxt_get_object_address(device, MXT_GEN_POWERCONFIG_T7, 0) + 0, 0x20); mxt_write_config_reg(device, mxt_get_object_address(device, MXT_GEN_POWERCONFIG_T7, 0) + 1, 0x10); mxt_write_config_reg(device, mxt_get_object_address(device, MXT_GEN_POWERCONFIG_T7, 0) + 2, 0x4b); mxt_write_config_reg(device, mxt_get_object_address(device, MXT_GEN_POWERCONFIG_T7, 0) + 3, 0x84); /* Write predefined configuration data to configuration objects */ mxt_write_config_object(device, mxt_get_object_address(device, MXT_GEN_ACQUISITIONCONFIG_T8, 0), &t8_object); mxt_write_config_object(device, mxt_get_object_address(device, MXT_TOUCH_MULTITOUCHSCREEN_T9, 0), &t9_object); mxt_write_config_object(device, mxt_get_object_address(device, MXT_SPT_CTE_CONFIGURATION_T46, 0), &t46_object); mxt_write_config_object(device, mxt_get_object_address(device, MXT_PROCI_SHIELDLESS_T56, 0), &t56_object); /* Issue recalibration command to maXTouch device by writing a non-zero * value to the calibrate register */ mxt_write_config_reg(device, mxt_get_object_address(device, MXT_GEN_COMMANDPROCESSOR_T6, 0) + MXT_GEN_COMMANDPROCESSOR_CALIBRATE, 0x01); }
//****************************************************************************** /// \brief Upload file to T68 Serial Data Object /// \return #mxt_rc int mxt_serial_data_upload(struct mxt_device *mxt, const char *filename, uint16_t datatype) { int ret; struct t68_ctx ctx; ctx.mxt = mxt; ctx.lc = mxt->ctx; ret = mxt_msg_reset(mxt); if (ret) return ret; mxt_info(ctx.lc, "Checking T7 Power Config"); ret = mxt_t68_check_power_cfg(&ctx); if (ret) return ret; /* Check for existence of T68 object */ ctx.t68_addr = mxt_get_object_address(mxt, SERIAL_DATA_COMMAND_T68, 0); if (ctx.t68_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; /* Calculate position of CMD register */ ctx.t68_size = mxt_get_object_size(mxt, SERIAL_DATA_COMMAND_T68); ctx.t68_cmd_addr = ctx.t68_addr + ctx.t68_size - 3; /* Calculate frame size */ ctx.t68_data_size = ctx.t68_size - 9; /* Set datatype from command line */ ctx.t68_datatype = datatype; /* Read input file */ ctx.filename = filename; ret = mxt_t68_load_file(&ctx); if (ret) return ret; ret = mxt_t68_enable(&ctx); if (ret) goto release; ret = mxt_t68_zero_data(&ctx); if (ret) goto release; ret = mxt_t68_write_length(&ctx, 0); if (ret) goto release; mxt_info(ctx.lc, "Configuring T68"); ret = mxt_t68_write_datatype(&ctx); if (ret) goto release; mxt_info(ctx.lc, "Sending data"); ret = mxt_t68_send_frames(&ctx); if (ret) { mxt_err(ctx.lc, "Error sending data"); goto release; } mxt_info(ctx.lc, "Done"); ret = MXT_SUCCESS; release: mxt_buf_free(&ctx.buf); return ret; }