Summary: I've had this bump in the road for one of my projects for a long time and I was wondering if anyone knew anything about it. I found a wonderful magnetic encoder (tle5012b) but I have had a lot of trouble hooking it up with the ESP32. The TLE5012B has a few options for interfaces but the primary one is SSC (which is just 3 wire SPI where the MOSI and MISO are tied together). It also has an incremental interface but I could not get the necessary accuracy from it. I wrote a micro python program to communicate with the TLE5012B over SPI communication. The code is below:
Code:
from machine import SPI, Pin
spi = SPI(1, 40000000, sck=Pin(14), mosi=Pin(13), miso=Pin(12)) #defining the SPI object
cs = Pin(19,mode=Pin.OUT, value=1) #defining chip select pin
rxdata = bytearray(4) #defining a 4 byte array
txdata = b'32801'
print(rxdata,"rxdata") #reading empty rx data as bit strings
print(txdata,"txdata") #reading tx data before sent as bit string
cs(0) # Select peripheral.
spi.write(txdata) # Write 8 bytes, and don't care about received data.
# Select peripheral.
spi.readinto(rxdata)#, 0x42) # Read 8 bytes inplace while writing 0x42 for each byte.
cs(1)
print(rxdata,"rxdata")
Schematic: This is how I wired the chip on the breadboard. I followed instructions I found online and data from the product datasheet. My Project Schematic
Problem: When running this code with this schematic, I receive an empty register and I don't really know how to move forward. Is there anything I am doing wrong?
Sources: Finally, here are all of the sources that I found might be remotely helpful
Code for someone who got it working on an Arduino Nano: https://forum.arduino.cc/t/arduino-spi-code-for-tle5012-magnetic-encoder-not-working-with-esp32/1144303
Micropython SPI tutorials: https://learn.adafruit.com/micropython-hardware-spi-devices/spi-main https://www.engineersgarage.com/micropython-esp8266-esp32-spi-software-spi/
Datasheet of component: file:///C:/Users/micha/Desktop/%C2%A0/Encoder/Infineon-Angle_Sensor_TLE5012B-UM-v01_02-en-UM-v01_02-EN.pdf
Register settings: (gives the register to read the data: 1000000000100001) https://www.infineon.com/dgdl/TLE5012B_Register_Setting_AN_Rev1.1.pdf?folderId=db3a30431ce5fb52011d29810c9e1b6a&fileId=db3a304330f68606013141cf6ae75690
Website with the circuit of TLE5012B for SPI: file:///C:/Users/micha/Desktop/%C2%A0/Encoder/SimpleBGC_32bit_Encoders.pdf
Thanks: I greatly appreciate anyone's help! Thank you so much! Sorry if I'm missing something obvious, I'm pretty new to all of this.
Already tried: I tried using the incremental interface as described in the datasheet but the ESP32 was not able to keep up and kept missing increments leading to wildly inaccurate data.
EDIT: I followed Mat's advice about not deselecting the chip right after the spi.write. I ran the adjusted code with the same problem of the rx register being empty. I still have some more issues in the code most likely or possibly I fried it as Mat warned.
I also changed the schematic slightly (just moving some resistors around)
I managed to solve it myself so here is the code for anyone that my want to use this object for their own projects. This sensor is pretty useful. Works like a charm.
from machine import Pin, SoftSPI
import time
class TLE5012B() :
def __init__(self,sck_pin=2,mosi_pin=13,miso_pin=15,cs_pin=4):
self.spi = SoftSPI(baudrate=8000000, sck=Pin(sck_pin), mosi=Pin(mosi_pin), miso=Pin(miso_pin)) #defining the SPI object
#self.spi.init()
self.cs = Pin(cs_pin,mode=Pin.OUT, value=1) #defining chip select pin
self.rotation_counter = 0
self.previous_angle = 0
self.start_angle = 0
self.zero()
def zero(self):
self.start_angle = self.get_angle_displacement()
def get_angle(self):
rxdata = bytearray(2) #defining a 4 byte array
command = '1000000000100001' #defining the command that reads the chip
txdata = int(command,2).to_bytes(2,'big') #converting to bytes
self.cs(0) #activating the chip through the chip select pin
self.spi.write(txdata) # Write the command which takes up two bytes
self.spi.readinto(rxdata)# Reading the data that was recieve from the chip and placing it the rx register
self.cs(1) #deactivating the chip once transaction is finished
byte1 = '{0:08b}'.format(rxdata[0]) #converting first bit to a string of ones and zeros
byte2 = '{0:08b}'.format(rxdata[1]) #converting second bit to a string of ones and zeros
data = byte1[1:]+byte2 #adding all of the strings together and extracting the angle data (total is a 15 bit number)
steps = int(data,2) #getting the 15 bit number as an integer
angle = (360*steps)/32768 #converting to angle
if ((self.previous_angle > 240) and (self.previous_angle <= 360)) and ((angle >= 0) and (angle < 120)):
self.rotation_counter += 1
elif ((angle > 240) and (angle <= 360)) and ((self.previous_angle >= 0) and (self.previous_angle < 120)):
self.rotation_counter -= 1
self.previous_angle = angle
return(angle)
def get_revs_slave(self):
rxdata = bytearray(4) #defining a 4 byte array
command = '1000000000110010' #defining the command that reads the chip
txdata = int(command,2).to_bytes(2,'big') #converting to bytes
self.cs(0) #activating the chip through the chip select pin
self.spi.write(txdata) # Write the command which takes up two bytes
self.spi.readinto(rxdata)# Reading the data that was recieve from the chip and placing it the rx register
self.cs(1) #deactivating the chip once transaction is finished
byte1 = '{0:08b}'.format(rxdata[2]) #converting third bit to a string of ones and zeros
byte2 = '{0:08b}'.format(rxdata[3]) #converting fourth bit to a string of ones and zeros
data_rev = byte1[-1]+byte2 #adding all of the strings together and extracting the rev data (total is a 9 bit number)
revs = int(data_rev,2) #getting the 9 bit number as an integer
return revs
def print_all_data(self,command):
#command = '1000000000100001' read angle command
#command = '1000000001000001' read revolutions command (TLE5012B Ragester Settings datasheet has more information https://www.infineon.com/dgdl/TLE5012B_Register_Setting_AN_Rev1.1.pdf?folderId=db3a30431ce5fb52011d29810c9e1b6a&fileId=db3a304330f68606013141cf6ae75690)
txdata2 = int(command,2).to_bytes(2,'big') #converting to bytes
rxdata2 = bytearray(10)
self.cs(0) #activating the chip through the chip select pin
self.spi.write(txdata2) # Write the command which takes up two bytes
self.spi.readinto(rxdata2)# Reading the data that was recieve from the chip and placing it the rx register
self.cs(1) #deactivating the chip once transaction is finished
for x in rxdata2:
print('{0:08b}'.format(x))
print("######################")
def get_revs_master(self):
return self.rotation_counter
def get_angle_displacement(self):
return self.get_angle() + (self.get_revs_master()*360) - self.start_angle
############################################################################
#Example
encoder = TLE5012B(sck_pin=2,mosi_pin=13,miso_pin=15,cs_pin=4) #defining sensor object
while True:#creating a loop to get live updates
#print(encoder.get_angle()) #printing sensor's position
#encoder.print_all_data('1000000000100001') #printing the binary that is returned from a certain command as a debugging tool
#print(encoder.get_revs_slave())
#print(encoder.get_revs_master())
print(encoder.get_angle_displacement())
time.sleep(.05) #control the speed of the loop by sleeping for .4 second
Here were the problems:
#1 The command was not converted from bits to bytes correctly. b'32801' does not equal '1000000000100001'
#2 The baud rate was incorrect
#3 the SPI object didn't work very well
Here are the solutions:
#1 This is how to convert bits to bytes properly
command = '1000000000100001'
txdata = int(command,2).to_bytes(2,'big')
#2 I changed the baud rate from 40000000 to 8000000 as specified in the datasheet.
#3 SoftSPI object magically worked for some reason.
Thanks yall!