#include "as5600.h" #include "math.h" #define cpr 4096 float full_rotation_offset; long angle_data_prev; unsigned long velocity_calc_timestamp; float angle_prev; /******************************************************************************/ void I2C_Init_(void) { GPIO_InitTypeDef GPIO_InitStructure; I2C_InitTypeDef I2C_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//GPIOB RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); I2C_DeInit(I2C1); I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = 0; //I2C_OAR1 I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = 400000; //400KHz I2C_Init(I2C1, &I2C_InitStructure); I2C_Cmd(I2C1, ENABLE); } /******************************************************************************/ /******************************************************************************/ #define AS5600_Address 0x36 #define RAW_Angle_Hi 0x0C /******************************************************************************/ unsigned short I2C_getRawCount(I2C_TypeDef* I2Cx) { uint32_t Timeout; unsigned short temp; unsigned char dh,dl; Timeout = 0xFFFF; I2Cx->CR1 |= 0x0100;//CR1_START_Set; /* Wait until SB flag is set: EV5 */ while ((I2Cx->SR1&0x0001) != 0x0001) { if (Timeout-- == 0)return 0; } /* Send the slave address, Reset the address bit0 for write*/ I2Cx->DR = AS5600_Address<<1; Timeout = 0xFFFF; /* Wait until ADDR is set: EV6 */ while ((I2Cx->SR1 &0x0002) != 0x0002) { if (Timeout-- == 0)return 0; } /* Clear ADDR flag by reading SR2 register */ temp = I2Cx->SR2; /* Write the first data in DR register (EV8_1) */ I2Cx->DR = RAW_Angle_Hi; /* EV8_2: Wait until BTF is set before programming the STOP */ while ((I2Cx->SR1 & 0x00004) != 0x000004); ///////////////////////////////////////////////////////////////////////// /* Set POS bit */ I2Cx->CR1 |= 0x0800;//CR1_POS_Set; Timeout = 0xFFFF; /* Send START condition */ I2Cx->CR1 |= 0x0100;//CR1_START_Set; /* Wait until SB flag is set: EV5 */ while ((I2Cx->SR1&0x0001) != 0x0001) { if (Timeout-- == 0)return 0; } Timeout = 0xFFFF; /* Send slave address */ I2Cx->DR = (AS5600_Address<<1)+1; /* Wait until ADDR is set: EV6 */ while ((I2Cx->SR1&0x0002) != 0x0002) { if (Timeout-- == 0)return 0; } /* EV6_1: The acknowledge disable should be done just after EV6, that is after ADDR is cleared, so disable all active IRQs around ADDR clearing and ACK clearing */ __disable_irq(); /* Clear ADDR by reading SR2 register */ temp = I2Cx->SR2; /* Clear ACK */ I2Cx->CR1 &= 0xFBFF;//CR1_ACK_Reset; /*Re-enable IRQs */ __enable_irq(); /* Wait until BTF is set */ while ((I2Cx->SR1 & 0x00004) != 0x000004); /* Disable IRQs around STOP programming and data reading because of the limitation ?*/ __disable_irq(); /* Program the STOP */ I2C_GenerateSTOP(I2Cx, ENABLE); /* Read first data */ dh = I2Cx->DR; /* Re-enable IRQs */ __enable_irq(); /**/ /* Read second data */ dl = I2Cx->DR; /* Make sure that the STOP bit is cleared by Hardware before CR1 write access */ while ((I2Cx->CR1&0x200) == 0x200); /* Enable Acknowledgement to be ready for another reception */ I2Cx->CR1 |= 0x0400;//CR1_ACK_Set; /* Clear POS bit */ I2Cx->CR1 &= 0xF7FF;//CR1_POS_Reset; temp++; //useless,otherwise warning return ((dh<<8)+dl); } /******************************************************************************/ void MagneticSensor_Init(void) { // angle_data_prev = I2C_getRawCount(I2C1); full_rotation_offset = 0; velocity_calc_timestamp=0; } //ΈΔ float getAngle(void) { float angle_data,d_angle; angle_data = I2C_getRawCount(I2C1); d_angle = angle_data - angle_data_prev; if(fabs(d_angle) > (0.8*cpr) ) full_rotation_offset += d_angle > 0 ? -_2PI : _2PI; angle_data_prev = angle_data; return (full_rotation_offset + ( angle_data / (float)cpr) * _2PI) ; } /******************************************************************************/ float getVelocity(void) { unsigned long now_us; float Ts, angle_c, vel; now_us = SysTick->VAL; if(now_us 0.5) Ts = 1e-3; angle_c = getAngle(); vel = (angle_c - angle_prev)/Ts; angle_prev = angle_c; velocity_calc_timestamp = now_us; return vel; } /******************************************************************************/