170 lines
4.7 KiB
C
170 lines
4.7 KiB
C
#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;
|
||
}
|
||
|
||
//<2F><>
|
||
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<velocity_calc_timestamp)Ts = (float)(velocity_calc_timestamp - now_us)/9*1e-6;
|
||
else
|
||
Ts = (float)(0xFFFFFF - now_us + velocity_calc_timestamp)/9*1e-6;
|
||
if(Ts == 0 || Ts > 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;
|
||
}
|
||
/******************************************************************************/
|
||
|