代码改变世界

角度传感器 TLB5012B

2018-05-30 18:27  TaoGePureYeahMan  阅读(1680)  评论(1编辑  收藏  举报

---恢复内容开始---

硬件将SPI时钟 DATA接口直接连接MAX490

1、DATA接口需要输出输出两个方向,输入指令、输出读数。而MAX490 TX只提供输出无法输入

2、即便TLB5012B可以通过SPI口控制,配置无需输入读数指令,也应当每次上电的时候连接SPI口,写入配置指令。

因而硬件需要调整。

使用SPI接口读写角度,使用BeagleBone Black 板调试SPI接口。

1、putty连接板子

2、BBB联网

以下内容应为内核升级不适用了

3、末尾添加行optargs=capemgr.enable_partno=BB-SPIDEV0

4、git clone https://github.com/5montest/BeagleBoneBlack_spi.git

5、./Enable_spidev.sh

6、。。。。。。。。。。。。。。。

https://blog.csdn.net/embbnux/article/details/38844957

3、使用以下方法驱动BBB的SPI接口

   将SPI设备插入槽中

  echo BB-SPIDEV0>/sys/devices/platform/bone_capemgr/slots
  

 BBB的SPI驱动如下:

  

/*
 * SPI testing utility (using spidev driver)
 *
 * Copyright (c) 2007  MontaVista Software, Inc.
 * Copyright (c) 2007  Anton Vorontsov <avorontsov@ru.mvista.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 2 of the License.
 *
 * Cross-compile with cross-gcc -I/path/to/cross-kernel/include
 */

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

static void pabort(const char *s)
{
    perror(s);
    abort();
}

static const char *device = "/dev/spidev1.1";
static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;

static void transfer(int fd)
{
    int ret;
    uint8_t tx[] = {
        0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
        0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,
        0xF0, 0x0D,
    };
    uint8_t rx[ARRAY_SIZE(tx)] = {0, };
    struct spi_ioc_transfer tr = {
        .tx_buf = (unsigned long)tx,
        .rx_buf = (unsigned long)rx,
        .len = ARRAY_SIZE(tx),
        .delay_usecs = delay,
        .speed_hz = speed,
        .bits_per_word = bits,
    };

    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
    if (ret < 1)
        pabort("can't send spi message");

    for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
        if (!(ret % 6))
            puts("");
        printf("%.2X ", rx[ret]);
    }
    puts("");
}

static void print_usage(const char *prog)
{
    printf("Usage: %s [-DsbdlHOLC3]\n", prog);
    puts("  -D --device   device to use (default /dev/spidev1.1)\n"
         "  -s --speed    max speed (Hz)\n"
         "  -d --delay    delay (usec)\n"
         "  -b --bpw      bits per word \n"
         "  -l --loop     loopback\n"
         "  -H --cpha     clock phase\n"
         "  -O --cpol     clock polarity\n"
         "  -L --lsb      least significant bit first\n"
         "  -C --cs-high  chip select active high\n"
         "  -3 --3wire    SI/SO signals shared\n");
    exit(1);
}

static void parse_opts(int argc, char *argv[])
{
    while (1) {
        static const struct option lopts[] = {
            { "device",  1, 0, 'D' },
            { "speed",   1, 0, 's' },
            { "delay",   1, 0, 'd' },
            { "bpw",     1, 0, 'b' },
            { "loop",    0, 0, 'l' },
            { "cpha",    0, 0, 'H' },
            { "cpol",    0, 0, 'O' },
            { "lsb",     0, 0, 'L' },
            { "cs-high", 0, 0, 'C' },
            { "3wire",   0, 0, '3' },
            { "no-cs",   0, 0, 'N' },
            { "ready",   0, 0, 'R' },
            { NULL, 0, 0, 0 },
        };
        int c;

        c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);

        if (c == -1)
            break;

        switch (c) {
        case 'D':
            device = optarg;
            break;
        case 's':
            speed = atoi(optarg);
            break;
        case 'd':
            delay = atoi(optarg);
            break;
        case 'b':
            bits = atoi(optarg);
            break;
        case 'l':
            mode |= SPI_LOOP;
            break;
        case 'H':
            mode |= SPI_CPHA;
            break;
        case 'O':
            mode |= SPI_CPOL;
            break;
        case 'L':
            mode |= SPI_LSB_FIRST;
            break;
        case 'C':
            mode |= SPI_CS_HIGH;
            break;
        case '3':
            mode |= SPI_3WIRE;
            break;
        case 'N':
            mode |= SPI_NO_CS;
            break;
        case 'R':
            mode |= SPI_READY;
            break;
        default:
            print_usage(argv[0]);
            break;
        }
    }
}

int main(int argc, char *argv[])
{
    int ret = 0;
    int fd;

    parse_opts(argc, argv);

    fd = open(device, O_RDWR);
    if (fd < 0)
        pabort("can't open device");

    /*
     * spi mode
     */
    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
    if (ret == -1)
        pabort("can't set spi mode");

    ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
    if (ret == -1)
        pabort("can't get spi mode");

    /*
     * bits per word
     */
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    if (ret == -1)
        pabort("can't set bits per word");

    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
    if (ret == -1)
        pabort("can't get bits per word");

    /*
     * max speed hz
     */
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    if (ret == -1)
        pabort("can't set max speed hz");

    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
    if (ret == -1)
        pabort("can't get max speed hz");

    printf("spi mode: %d\n", mode);
    printf("bits per word: %d\n", bits);
    printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);

    transfer(fd);

    close(fd);

    return ret;
}

  TLE的STM32驱动如下:

  

/**
  ******************************************************************************
  * @file    spi_TLE5012B.c
  * @author  Keith Cheung
  * @version V3.5.0
  * @date    13-MAY-2017
  * @brief   This file contains the headers of the spi_TLE5012B.
  ******************************************************************************
  * @attention
  *
  *
  * <h2><center>&copy; COPYRIGHT 2017</center></h2>
  ******************************************************************************
  */
    
#include "stm32f10x.h"
#include "spi_TLE5012B.h"
//#include "PublicSet.h"

//uint16_t TLE_Angle,Angle_Speed,TLE_Offset_Angle;

//spi_TLE5012B.H 中有简要说明

void Delay( uint16_t i )
{
   while( i-- );
}


void SPI5012B_Init(void)
{
    SPI_InitTypeDef  SPI_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1,ENABLE );
    
    //以下二句,在它处声明,请增加使用
    //RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD |RCC_APB2Periph_AFIO, ENABLE);
    //GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);//使JTDO、JTDI、JTCK 当成普通IO口进行操作
    //GPIOB0 当成普通IO口进行操作
    
    /*SPI: NSS,SCK,MISO and MOSI */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//PA5--CLK--复用推挽
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    //GPIO_StructInit(&GPIO_InitStructure);
    
    /* Configure PA6 as encoder input */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//PA6--MISO--输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    /* PA7*/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//PA7--MOSI--推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_CS_Pin_Name;//PB0--CS--推挽输出
    GPIO_Init(GPIO_CS_Pin_Type, &GPIO_InitStructure);
    
    /**********SPI****************/
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//SPI1--双线全双工!!
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    
    SPI_Init(SPI1, &SPI_InitStructure);
    SPI_Cmd(SPI1, ENABLE);
}


uint16_t SPIx_ReadWriteByte(uint16_t byte)
{
    uint16_t retry = 0;
    while( (SPI1->SR&1<<1) == 0 )//发送缓冲区非空
    {
        if( ++retry > 200 )
            return 0;//延迟一段时间后返回
    }
    SPI1->DR = byte;     //发送数据
    
    retry = 0;
    while( (SPI1->SR&1<<0) == 0 ) //接收缓冲区为空
    {
        if( ++retry > 200 )
            return 0;//延迟一段时间后返回
    }
    return SPI1->DR;          //读一下缓冲区,清标志
}


//得到 0~359 度
uint16_t ReadAngle(void)
{
    return ( ReadValue(READ_ANGLE_VALUE) * 360 / 0x10000 );
}

//得到角速度
uint16_t ReadSpeed(void)
{
    return ReadValue(READ_SPEED_VALUE);
}


uint16_t ReadValue(uint16_t u16RegValue)
{
    uint16_t u16Data;

    SPI_CS_ENABLE;
    
    SPIx_ReadWriteByte(u16RegValue);
  SPI_TX_OFF;
    
    //发送 0xFFFF 是无用的,可能是为了有时钟
    u16Data = ( SPIx_ReadWriteByte(0xffff) & 0x7FFF ) << 1;//0x12/0xff*100k
    
    SPI_CS_DISABLE;
  SPI_TX_ON;
    
    return(u16Data);
}
/**
  ******************************************************************************
  * @file    spi_TLE5012B.h 
  * @author  Keith Cheung
  * @version V3.5.0
  * @date    13-MAY-2017
  * @brief   This file contains the headers of the spi_TLE5012B.
  ******************************************************************************
  * @attention
  *
  *
  * <h2><center>&copy; COPYRIGHT 2017</center></h2>
  ******************************************************************************
  */
    
#ifndef _TLE5012B_H_
#define _TLE5012B_H_

#include "stm32f10x.h"

//extern uint16_t TLE_Angle, Angle_Speed, TLE_Offset_Angle;
/*
TLE5012B_E1000 接线说明:

1:NC
2:SCK <= 120R => stm32f103 PA5
3:CSQ (CS) <= 120R => stm32f103 PB0
4:DATA <= 120R => stm32f103 PA6
  DATA <= 120R => stm32f103 PA7
  DATA <= 2.2K => Vdd 3.3V
  PS:因是三线 SPI , MOSI , MISO 并线使用

5:NC
6:Vdd 3.3V
7:GND
8:NC
*/

//磁铁,请用“径向充磁”的圆磁铁,如 直径 10 x 厚 2mm

//SPI5012B_Init() 时钟需另外加上

//以下内容需按实际更改
#define SPI_TX_OFF {GPIOA->CRL&=0x0FFFFFFF;GPIOA->CRL|=0x40000000;}//把PA7(MOSI)配置成开漏--输入模式
#define SPI_TX_ON  {GPIOA->CRL&=0x0FFFFFFF;GPIOA->CRL|=0xB0000000;}//把PA7(MOSI)配置成推挽--输出模式(50MHz)

#define GPIO_CS_Pin_Name  GPIO_Pin_0
#define GPIO_CS_Pin_Type  GPIOB

//以下内容一般不需变动
#define SPI_CS_ENABLE  GPIO_ResetBits(GPIO_CS_Pin_Type, GPIO_CS_Pin_Name)       //片选脚电平拉低
#define SPI_CS_DISABLE GPIO_SetBits(GPIO_CS_Pin_Type, GPIO_CS_Pin_Name)         //片选脚电平拉高
//#define INDEX_ENABLE   GPIO_SetBits(GPIOA, GPIO_Pin_4)/* for incremental signal index */

//#define CLK_H GPIO_SetBits(GPIOA, GPIO_Pin_5)                 //时钟脚PA5电平拉高
//#define CLK_L GPIO_ResetBits(GPIOA, GPIO_Pin_5)               //时钟脚PA5电平拉低

//#define DATA_H    GPIO_SetBits(GPIOA, GPIO_Pin_6)                         //PA6(MISO)电平拉高
//#define DATA_L    GPIO_ResetBits(GPIOA, GPIO_Pin_6)                       //PA6(MISO)电平拉低
//#define READ_DATA    GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6)

/* SPI command for TLE5012 */
#define READ_STATUS                    0x8001            //8000
#define READ_ANGLE_VALUE        0x8021            //8020
#define READ_SPEED_VALUE        0x8031            //8030

#define WRITE_MOD1_VALUE        0x5060                            //0_1010_0_000110_0001
#define MOD1_VALUE    0x0001

#define WRITE_MOD2_VALUE        0x5080                            //0_1010_0_001000_0001
#define MOD2_VALUE    0x0801

#define WRITE_MOD3_VALUE        0x5091                            //0_1010_0_001001_0001
#define MOD3_VALUE    0x0000

#define WRITE_MOD4_VALUE        0x50E0                            //0_1010_0_001110_0001
#define MOD4_VALUE    0x0098                //9bit 512

#define WRITE_IFAB_VALUE        0x50B1
#define IFAB_VALUE 0x000D
/* Functionality mode */
#define REFERESH_ANGLE        0

void SPI5012B_Init(void);
void SPI_SendData16(uint16_t SendData);
uint16_t SPI_ReadData16(void);
uint16_t ReadAngle(void);
uint16_t ReadSpeed(void);
uint16_t ReadValue(uint16_t u16Value);
uint16_t SPIx_ReadWriteByte(uint16_t byte);
uint16_t TlE5012W_Reg(uint16_t Reg_CMD, uint16_t Reg_Data);
#endif

然而BBB的SPI是标准SPI自环结果如下图所示

TLE5012 是3线SSC接口 需要硬件和驱动方面的更改

硬件方面

1.硬件:

   A. 英飞凌磁传感器 TLE5012bE1000

   B. STM32F103

   C. 磁铁,请用“径向充磁”的圆磁铁,如 直径 10 x 厚 2mm,找TB买

2.TLE5012B_E1000 接线说明:

1:NC
2:SCK <= 120R => stm32f103 PA5
3:CSQ (CS) <= 120R => stm32f103 PB0
4:DATA <= 120R => stm32f103 PA6
  DATA <= 120R => stm32f103 PA7
  DATA <= 2.2K => Vdd 3.3V
  PS:因是三线 SPI , MOSI , MISO 并线使用
 
5:NC
6:Vdd 3.3V
7:GND
8:NC

 

 

思路 ,需要将BBB的驱动进行修改,四线改为三线、参考https://e2echina.ti.com/question_answer/dsp_arm/sitara_arm/f/25/t/80526

 

 

只要线接对,使用随处可见的驱动读数即可。需要将读数改成小数,结束。那个磁铁随便试了一下。读数/65535