最近公司在关节模组上面使用的一款磁编码器IC-MU128和IC-MU200。该芯片是使用BISS或者SPI去通信的。由于我使用的是STM32作为MCU,所以只能使用SPI去通信。

        由于目前我还不是很熟悉这款芯片,等后面供应商过来校准后,开发更详细的资料后,后续我还会再写一篇文档补充,目前只是记录一下如何验证该款芯片的通信。

        目前和供应商那边沟通的情况是,SPI通信波特率小于10Mbit即可,具体多少手册上面也没有写。

        从手册上面了解到的是该款芯片是只支持SPI0和SPI3模式。目前的话我使用的是软件SPI去验证通信的,没有使用硬件SPI的原因很简单,硬件工程师那边画错了。

         (1)软件SPI验证IC-MU磁编码器:

        下面是bsp_spi.h的内容:

#ifndef __BSP_SPI_H
#define __BSP_SPI_H
#include "main.h"
#include "bsp_delay.h"
 
#define SPI_SCK_PIN                     GPIO_PIN_4
#define SPI_SCK_GPIO_PORT               GPIOB
#define SPI_MOSI_PIN                    GPIO_PIN_5
#define SPI_MOSI_GPIO_PORT              GPIOB
#define SPI_MISO_PIN                    GPIO_PIN_2
#define SPI_MISO_GPIO_PORT              GPIOB
#define SPI_NSS_PIN                     GPIO_PIN_3
#define SPI_NSS_GPIO_PORT               GPIOB
 
#define MOSI_H  HAL_GPIO_WritePin(SPI_MOSI_GPIO_PORT, SPI_MOSI_PIN, GPIO_PIN_SET)  
#define MOSI_L  HAL_GPIO_WritePin(SPI_MOSI_GPIO_PORT, SPI_MOSI_PIN, GPIO_PIN_RESET)  
#define SCK_H   HAL_GPIO_WritePin(SPI_SCK_GPIO_PORT, SPI_SCK_PIN, GPIO_PIN_SET)  
#define SCK_L   HAL_GPIO_WritePin(SPI_SCK_GPIO_PORT, SPI_SCK_PIN, GPIO_PIN_RESET)  
#define MISO    HAL_GPIO_ReadPin(SPI_MISO_GPIO_PORT, SPI_MISO_PIN) 
#define NSS_H   HAL_GPIO_WritePin(SPI_NSS_GPIO_PORT, SPI_NSS_PIN, GPIO_PIN_SET)  
#define NSS_L   HAL_GPIO_WritePin(SPI_NSS_GPIO_PORT, SPI_NSS_PIN, GPIO_PIN_RESET)
 
uint8_t SOFT_SPI_RW_MODE0(uint8_t write_dat);
#endif

        下面是bsp_spi.c的内容:

#include "bsp_spi.h"
 
uint8_t SOFT_SPI_RW_MODE0( uint8_t write_dat )
{
    uint8_t i, read_dat;
    for( i = 0; i < 8; i++ )
    {
        if( write_dat & 0x80 )
            MOSI_H;  
        else                    
            MOSI_L;  
        write_dat <<= 1;
        SCK_H; 
        read_dat <<= 1;  
        if( MISO ) 
            read_dat++; 
        SCK_L; 
        __nop();
    }
	
    return read_dat;
}

        直接找个地方调用接口函数去发送0xA6即可,不需要发送0xB0去ACTIVATE也能通信。

        目前的话IC-MU200/IC-MU128磁编码器的位数都是14位的,有效数据的大小和磁盘也有关系。比如我使用的磁盘是32对极的(2^5)。那么就代表这磁编码器的有效数据是14+5 = 19位。发现字节去获取数据的时候,返回的24bit的数据需要右移5位才是真实的数据。

        (2)硬件SPI验证IC-MU编码器

#include "ic_mu.h"
#include "mc_type.h"
#include "mc_config.h"
#include "PIC32SPIDriver.h"
#include "abs_encoder_pos_fdbk.h"
#include "pmsm_motor_parameters.h"

typedef ENCODER_Handle_t IC_MU128_Handle;
typedef SpeednPosFdbk_Handle_t IC_MU200_Handle;

void IC_MU_H( void * pHdl, IC_MU_TYPE_t SensorType );
void IC_MU_L( void * pHdl, IC_MU_TYPE_t SensorType );

uint8_t wdata[4]  = {0xA6,0xFF,0xFF,0xFF};
uint8_t rHdata[4] = {0};
uint8_t rLdata[4] = {0};

uint32_t SPI_Send( void * pHdl ,IC_MU_TYPE_t SensorType )
{
	uint32_t rtdata;
	
	ENCODER_Handle_t * pHandle = (ENCODER_Handle_t *)pHdl;
	
	if( SensorType == IC_MU_128 )
	{
		IC_MU128_Handle * Handle = pHandle;
		
		if(Handle->hspi != MC_NULL)
		{
			HAL_SPI_TransmitReceive_IT(Handle->hspi,wdata,rLdata,4);
			rtdata = Handle->wRawAngleData;
		}
	}
	else if (SensorType == IC_MU_200 )
	{
		IC_MU200_Handle * Handle = &pHandle->_Super;
		
		if(Handle->hspi != MC_NULL)
		{
			HAL_SPI_TransmitReceive_IT(Handle->hspi,(uint8_t *)&wdata,rHdata,4);
			rtdata = Handle->hRawAngleData;
		}
	}
	
  return rtdata;
}


void IC_MU_H( void * pHdl, IC_MU_TYPE_t SensorType )
{
	ENCODER_Handle_t * pHandle = (ENCODER_Handle_t *)pHdl;
	
	if( SensorType == IC_MU_128 )
	{
		IC_MU128_Handle * Handle = pHandle;
		if(Handle->hspi != MC_NULL) SPI1_CS_H;
	}
	else if(SensorType == IC_MU_200)
	{
		IC_MU200_Handle * Handle = &pHandle->_Super;
		if(Handle->hspi != MC_NULL) SPI2_CS_H;
	}
}

void IC_MU_L( void * pHdl, IC_MU_TYPE_t SensorType)
{
	ENCODER_Handle_t * pHandle = (ENCODER_Handle_t *)pHdl;
	
	if( SensorType == IC_MU_128 )
	{
		IC_MU128_Handle * Handle = pHandle;
		if(Handle->hspi != MC_NULL) SPI1_CS_L;
	}
	else if(SensorType == IC_MU_200)
	{
		IC_MU200_Handle * Handle = &pHandle->_Super;
		if(Handle->hspi != MC_NULL) SPI2_CS_L;
	}
}

uint32_t SPI_IC_MU128(void * pHandle)
{
	uint32_t theta;
	IC_MU_L(pHandle,IC_MU_128);
	theta = SPI_Send(pHandle,IC_MU_128);
	return theta;
}

uint32_t SPI_IC_MU200(void * pHandle)
{
	uint32_t theta;
	IC_MU_L(pHandle,IC_MU_200);
	theta = SPI_Send(pHandle,IC_MU_200);
	return theta;
}

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
	if(hspi->Instance == SPI1)
	{
		SPI1_CS_H;
		Encoder_M1.wRawAngleData = (( rLdata[1] << 16 | rLdata[2] << 8 | rLdata[3] << 0 ) & 0xFFFFFF ) >> 5;
	}
	if(hspi->Instance == SPI2)
	{
		SPI2_CS_H;
		Encoder_M1._Super.hRawAngleData = (( rHdata[1] << 16 | rHdata[2] << 8 | rHdata[3] << 0 ) & 0xFFFFFF ) >> 5;
	}
	if(hspi->Instance == SPI3)
	{
	}
}

        在进行通信之前将SPI_CS片选引脚拉低,使用SPI中断相关的中断中断函数HAL_SPI_TransmitReceive_IT(Handle->hspi,wdata,rLdata,4);进行数据发送,在中断回调函数里面将SPI_CS片选引脚拉高即可。
        可以写一个数据 uint8_t wdata[4]  = {0xA6,0xFF,0xFF,0xFF};  一次性发送四个字节,这样字节和字节间的通信间隔不会太长。
        还有就是片选引脚问题,通信之前片选引脚一定要是高片选,通信前要拉低,通过测试发现可能芯片IC-MU可能需要识别片选引脚来判断触发通信。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐