mirror of
https://github.com/EFeru/hoverboard-sideboard-hack-GD.git
synced 2025-07-27 09:39:33 +00:00
337 lines
15 KiB
C
337 lines
15 KiB
C
/**
|
|
* This file is part of the hoverboard-sideboard-hack project.
|
|
*
|
|
* Copyright (C) 2020-2021 Emanuel FERU <aerdronix@gmail.com>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
#include "gd32f1x0_i2c.h"
|
|
#include "i2c_it.h"
|
|
#include "util.h"
|
|
#include "systick.h"
|
|
#include "config.h"
|
|
|
|
void I2C0_EventIRQ_Handler(void)
|
|
{
|
|
uint16_t k;
|
|
if (i2c_ReadWriteCmd == WRITE) { // check for WRITE command
|
|
|
|
// ======================================== WRITE ========================================
|
|
// --------------------------------------------------------------------
|
|
// | Master | S | AD+W | | RA | | DATA | | DATA | | P |
|
|
// | Slave | | | ACK | | ACK | | ACK | | ACK | |
|
|
// --------------------------------------------------------------------
|
|
|
|
if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SBSEND)) { // check if start condition is sent out in master mode
|
|
|
|
i2c_master_addressing(I2C0, i2c_slaveAddress, I2C_TRANSMITTER); // send slave address with Transmit request
|
|
|
|
} else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND)) { // check if address is sent in master mode
|
|
|
|
i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND); // clear ADDSEND bit
|
|
|
|
} else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE)) { // check if I2C_DATA is empty (Transmitted Byte Empty)
|
|
|
|
if (i2c_nRABytes > 0) { // check if the Register Address has been sent
|
|
i2c_data_transmit(I2C0, i2c_regAddress); // the master sends the Register Address byte
|
|
i2c_nRABytes--;
|
|
} else {
|
|
if (i2c_nDABytes > 0) {
|
|
i2c_data_transmit(I2C0, *i2c_txbuffer++); // the master sends a data byte
|
|
i2c_nDABytes--;
|
|
for(k=0; k<500; k++); // make some clock cycles delay (otherwise DMP writing will fail!! Reason unknown yet.. could be that writing to MPU6050 memory takes a bit more time)
|
|
} else {
|
|
i2c_stop_on_bus(I2C0); // the master sends a stop condition to I2C bus
|
|
i2c_status = 0; // 0 = Success
|
|
i2c_interrupt_disable(I2C0, I2C_INT_ERR | I2C_INT_BUF | I2C_INT_EV); // disable the I2C0 interrupt
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
} else if (i2c_ReadWriteCmd == READ) { // check for READ command
|
|
|
|
// ======================================== READ ========================================
|
|
// --------------------------------------------------------------------------------------
|
|
// | Master | S | AD+W | | RA | | S | AD+R | | ACK | | NACK | P |
|
|
// | Slave | | | ACK | | ACK | | | ACK | DATA | | DATA | | |
|
|
// --------------------------------------------------------------------------------------
|
|
// <---------- Phase 1 ----------> <---------------- Phase 2 ---------------->
|
|
|
|
// Phase 1 - send the Register Address
|
|
if (i2c_nRABytes >= 0) {
|
|
|
|
if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SBSEND)) { // check if start condition is sent out in master mode
|
|
|
|
i2c_master_addressing(I2C0, i2c_slaveAddress, I2C_TRANSMITTER); // send slave address with Transmit request
|
|
|
|
} else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND)) { // check if address is sent in master mode
|
|
|
|
i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND); // clear ADDSEND bit
|
|
|
|
} else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE)) { // check if I2C_DATA is empty (Transmitted Byte Empty)
|
|
if (i2c_nRABytes > 0) { // check RABytes
|
|
i2c_data_transmit(I2C0, i2c_regAddress); // the master sends the Register Address byte
|
|
} else {
|
|
i2c_start_on_bus(I2C0); // send start condition
|
|
}
|
|
i2c_nRABytes--;
|
|
}
|
|
|
|
// Phase 2 - read Data
|
|
} else {
|
|
|
|
if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SBSEND)){ // check if start condition is sent out in master mode
|
|
|
|
i2c_master_addressing(I2C0, i2c_slaveAddress, I2C_RECEIVER); // sends slave address with Receive Request
|
|
|
|
}else if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND)){ // check if address is sent in master mode
|
|
|
|
if((1 == i2c_nDABytes) || (2 == i2c_nDABytes)){
|
|
i2c_ack_config(I2C0, I2C_ACK_DISABLE); // clear the ACKEN before the ADDSEND is cleared
|
|
i2c_interrupt_flag_clear(I2C0,I2C_INT_FLAG_ADDSEND); // clear the ADDSEND bit
|
|
}else{
|
|
i2c_interrupt_flag_clear(I2C0,I2C_INT_FLAG_ADDSEND); // clear the ADDSEND bit
|
|
}
|
|
|
|
}else if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_RBNE)){ // check if I2C_DATA is not Empty (Received Byte Not Empty)
|
|
if(i2c_nDABytes > 0){
|
|
if(3 == i2c_nDABytes){
|
|
while(!i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_BTC)); // wait until the second last data byte is received into the shift register
|
|
i2c_ack_config(I2C0, I2C_ACK_DISABLE); // send a NACK for the last data byte
|
|
}
|
|
*i2c_rxbuffer++ = i2c_data_receive(I2C0); // read a data byte from I2C_DATA
|
|
i2c_nDABytes--;
|
|
if(0 == i2c_nDABytes){
|
|
i2c_stop_on_bus(I2C0); // send a stop condition
|
|
i2c_status = 0; // 0 = Success
|
|
i2c_ack_config(I2C0, I2C_ACK_ENABLE);
|
|
i2c_ackpos_config(I2C0, I2C_ACKPOS_CURRENT);
|
|
i2c_interrupt_disable(I2C0, I2C_INT_ERR | I2C_INT_BUF | I2C_INT_EV);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void I2C0_ErrorIRQ_Handler(void)
|
|
{
|
|
/* no acknowledge received */
|
|
if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_AERR)){
|
|
i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_AERR);
|
|
}
|
|
|
|
/* SMBus alert */
|
|
if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SMBALT)){
|
|
i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_SMBALT);
|
|
}
|
|
|
|
/* bus timeout in SMBus mode */
|
|
if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SMBTO)){
|
|
i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_SMBTO);
|
|
}
|
|
|
|
/* over-run or under-run when SCL stretch is disabled */
|
|
if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_OUERR)){
|
|
i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_OUERR);
|
|
}
|
|
|
|
/* arbitration lost */
|
|
if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_LOSTARB)){
|
|
i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_LOSTARB);
|
|
}
|
|
|
|
/* bus error */
|
|
if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_BERR)){
|
|
i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_BERR);
|
|
}
|
|
|
|
/* CRC value doesn't match */
|
|
if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_PECERR)){
|
|
i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_PECERR);
|
|
}
|
|
/* disable the error interrupt */
|
|
i2c_interrupt_disable(I2C0,I2C_INT_ERR | I2C_INT_BUF | I2C_INT_EV);
|
|
}
|
|
|
|
|
|
#ifdef AUX45_USE_I2C
|
|
/*!
|
|
\brief handle I2C1 event interrupt request
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void I2C1_EventIRQ_Handler(void)
|
|
{
|
|
uint16_t k;
|
|
if (i2c_aux_ReadWriteCmd == WRITE) { // check for WRITE command
|
|
|
|
// ======================================== WRITE ========================================
|
|
// --------------------------------------------------------------------
|
|
// | Master | S | AD+W | | RA | | DATA | | DATA | | P |
|
|
// | Slave | | | ACK | | ACK | | ACK | | ACK | |
|
|
// --------------------------------------------------------------------
|
|
|
|
if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_SBSEND)) { // check if start condition is sent out in master mode
|
|
|
|
i2c_master_addressing(I2C1, i2c_aux_slaveAddress, I2C_TRANSMITTER); // send slave address with Transmit request
|
|
|
|
} else if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_ADDSEND)) { // check if address is sent in master mode
|
|
|
|
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_ADDSEND); // clear ADDSEND bit
|
|
|
|
} else if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_TBE)) { // check if I2C_DATA is empty (Transmitted Byte Empty)
|
|
|
|
if (i2c_aux_nRABytes > 0) { // check if the Register Address has been sent
|
|
i2c_data_transmit(I2C1, i2c_aux_regAddress); // the master sends the Register Address byte
|
|
i2c_aux_nRABytes--;
|
|
} else {
|
|
if (i2c_aux_nDABytes > 0) {
|
|
i2c_data_transmit(I2C1, *i2c_aux_txbuffer++); // the master sends a data byte
|
|
i2c_aux_nDABytes--;
|
|
for(k=0; k<500; k++); // make some clock cycles delay (otherwise DMP writing will fail!! Reason unknown yet.. could be that writing to MPU6050 memory takes a bit more time)
|
|
} else {
|
|
i2c_stop_on_bus(I2C1); // the master sends a stop condition to I2C bus
|
|
i2c_aux_status = 0; // 0 = Success
|
|
i2c_interrupt_disable(I2C1, I2C_INT_ERR | I2C_INT_BUF | I2C_INT_EV); // disable the I2C0 interrupt
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
} else if (i2c_aux_ReadWriteCmd == READ) { // check for READ command
|
|
|
|
// ======================================== READ ========================================
|
|
// --------------------------------------------------------------------------------------
|
|
// | Master | S | AD+W | | RA | | S | AD+R | | ACK | | NACK | P |
|
|
// | Slave | | | ACK | | ACK | | | ACK | DATA | | DATA | | |
|
|
// --------------------------------------------------------------------------------------
|
|
// <---------- Phase 1 ----------> <---------------- Phase 2 ---------------->
|
|
|
|
// Phase 1 - send the Register Address
|
|
if (i2c_aux_nRABytes >= 0) {
|
|
|
|
if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_SBSEND)) { // check if start condition is sent out in master mode
|
|
|
|
i2c_master_addressing(I2C1, i2c_aux_slaveAddress, I2C_TRANSMITTER); // send slave address with Transmit request
|
|
|
|
} else if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_ADDSEND)) { // check if address is sent in master mode
|
|
|
|
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_ADDSEND); // clear ADDSEND bit
|
|
|
|
} else if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_TBE)) { // check if I2C_DATA is empty (Transmitted Byte Empty)
|
|
if (i2c_aux_nRABytes > 0) { // check RABytes
|
|
i2c_data_transmit(I2C1, i2c_aux_regAddress); // the master sends the Register Address byte
|
|
} else {
|
|
i2c_start_on_bus(I2C1); // send start condition
|
|
}
|
|
i2c_aux_nRABytes--;
|
|
}
|
|
|
|
// Phase 2 - read Data
|
|
} else {
|
|
|
|
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_SBSEND)){ // check if start condition is sent out in master mode
|
|
|
|
i2c_master_addressing(I2C1, i2c_aux_slaveAddress, I2C_RECEIVER); // sends slave address with Receive Request
|
|
|
|
}else if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_ADDSEND)){ // check if address is sent in master mode
|
|
|
|
if((1 == i2c_aux_nDABytes) || (2 == i2c_aux_nDABytes)){
|
|
i2c_ack_config(I2C1, I2C_ACK_DISABLE); // clear the ACKEN before the ADDSEND is cleared
|
|
i2c_interrupt_flag_clear(I2C1,I2C_INT_FLAG_ADDSEND); // clear the ADDSEND bit
|
|
}else{
|
|
i2c_interrupt_flag_clear(I2C1,I2C_INT_FLAG_ADDSEND); // clear the ADDSEND bit
|
|
}
|
|
|
|
}else if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_RBNE)){ // check if I2C_DATA is not Empty (Received Byte Not Empty)
|
|
if(i2c_aux_nDABytes > 0){
|
|
if(3 == i2c_aux_nDABytes){
|
|
while(!i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_BTC)); // wait until the second last data byte is received into the shift register
|
|
i2c_ack_config(I2C1, I2C_ACK_DISABLE); // send a NACK for the last data byte
|
|
}
|
|
*i2c_aux_rxbuffer++ = i2c_data_receive(I2C1); // read a data byte from I2C_DATA
|
|
i2c_aux_nDABytes--;
|
|
if(0 == i2c_aux_nDABytes){
|
|
i2c_stop_on_bus(I2C1); // send a stop condition
|
|
i2c_aux_status = 0; // 0 = Success
|
|
i2c_ack_config(I2C1, I2C_ACK_ENABLE);
|
|
i2c_ackpos_config(I2C1, I2C_ACKPOS_CURRENT);
|
|
i2c_interrupt_disable(I2C1, I2C_INT_ERR | I2C_INT_BUF | I2C_INT_EV);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief handle I2C1 error interrupt request
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void I2C1_ErrorIRQ_Handler(void)
|
|
{
|
|
/* no acknowledge received */
|
|
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_AERR)){
|
|
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_AERR);
|
|
}
|
|
|
|
/* SMBus alert */
|
|
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_SMBALT)){
|
|
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_SMBALT);
|
|
}
|
|
|
|
/* bus timeout in SMBus mode */
|
|
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_SMBTO)){
|
|
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_SMBTO);
|
|
}
|
|
|
|
/* over-run or under-run when SCL stretch is disabled */
|
|
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_OUERR)){
|
|
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_OUERR);
|
|
}
|
|
|
|
/* arbitration lost */
|
|
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_LOSTARB)){
|
|
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_LOSTARB);
|
|
}
|
|
|
|
/* bus error */
|
|
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_BERR)){
|
|
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_BERR);
|
|
}
|
|
|
|
/* CRC value doesn't match */
|
|
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_PECERR)){
|
|
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_PECERR);
|
|
}
|
|
/* disable the error interrupt */
|
|
i2c_interrupt_disable(I2C0,I2C_INT_ERR | I2C_INT_BUF | I2C_INT_EV);
|
|
}
|
|
#endif
|
|
|