---恢复内容开始---
硬件将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>© 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>© 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接口 需要硬件和驱动方面的更改
硬件方面
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