This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TMAG5170UEVM:EVM 的最大读取速率

Guru**** 1120820 points
Other Parts Discussed in Thread: TI-SCB, INA228, TMAG5170
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/sensors-group/sensors/f/sensors-forum/1109939/tmag5170uevm-maximum-readout-rate-for-evm

器件型号:TMAG5170UEVM
主题中讨论的其他器件:TI-SCBINA228TMAG5170

您好!

目前、我正在使用 TI-SCB 评估 TMAG5170A1器件、使用 Python 脚本(UART、921600)读取数据并将其另存为 MAT 文件。

尽管器件配置为4x - 3.1Ksps (3轴)/25mT / mag_ch_en = 9 (xyz)、但读数速度似乎很低(所有3轴为~500Hz)。 写入器件的寄存器00-03为0x2000、0x25C0、0x0200和0x0000。

我是否可以知道此 EVM 的最大读取速率是多少?

如果需要、可以提供 Python 脚本。

最棒的

套件

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    套件、

    我理解这可能会造成的困难。  我认为它与发送到 TI-SCB 以启动读取的命令结构有关。  同时使用单独的寄存器读取可能会非常慢。  为了更好地了解您与 TI-SCB 的连接方式、查看您的 Python 脚本会很有用。   

    谢谢、

    Scott

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Scott、

    请检查附件。 有两个线程、一个线程用于 matplotlib 动画(每200ms 刷新一次)、另一个线程用于串行读取和解码。 在 Ctrl+C 之后、脚本将退出并将列表另存为 mat 文件。

    import random
    from urllib3 import add_stderr_logger
    import queue
    import matplotlib.animation as animation
    import matplotlib.pyplot as plt
    import serial
    import json
    import time
    import logging
    from time import sleep
    import threading
    import signal
    from scipy.io import savemat
    import matplotlib
    matplotlib.use('TkAgg')
    
    # plt.switch_backend('agg')
    
    plot_queue = queue.Queue()
    plot_start_semaphore = threading.Semaphore(0)
    sample_start_sem = threading.Semaphore(0)
    will_exit = False
    
    global x_val
    global y_val
    global z_val
    x_val = []
    y_val = []
    z_val = []
    
    global x_val_all
    global y_val_all
    global z_val_all
    x_val_all = []
    y_val_all = []
    z_val_all = []
    timestamp_nsval = []
    
    # Plot Parameters
    mtscale = 25
    t_len = 5000         # Number of points to display
    y_range = [-1*mtscale, mtscale]  # Range of possible Y values to display
    z_range = [-1*mtscale, mtscale]  # Range of possible Z values to display
    fig = plt.figure(figsize=[12, 10], dpi=300)
    ax = fig.add_subplot(1, 3, 1)
    ay = fig.add_subplot(1, 3, 2)
    az = fig.add_subplot(1, 3, 3)
    
    ts = list(range(0, t_len))
    
    xs = [0] * t_len
    ys = [0] * t_len
    zs = [0] * t_len
    
    lineax = ax.plot(ts, xs)[0]
    lineay = ay.plot(ts, ys)[0]
    lineaz = az.plot(ts, ys)[0]
    
    try:
        s = serial.Serial('COM7', 921600, timeout=1)
    except:
        raise Exception("serial cannot open")
    else:
        logging.info("Serial: OK")
        # s.close()
    
    
    def current_milli_time():
        return round(time.time() * 1000)
    
    
    class ReadLine:
        def __init__(self, s):
            self.buf = bytearray()
            self.s = s
    
        def readline(self):
            i = self.buf.find(b"\n")
            if i >= 0:
                r = self.buf[:i+1]
                self.buf = self.buf[i+1:]
                return r
            while True:
                i = max(1, min(2048, self.s.in_waiting))
                data = self.s.read(i)
                i = data.find(b"\n")
                if i >= 0:
                    r = self.buf + data[:i+1]
                    self.buf[0:] = data[i+1:]
                    return r
                else:
                    self.buf.extend(data)
    
    
    def writetmag(tx, reader, addr, value, logprint=None):
        # purge all incoming data
        lineindex = 0
        resp_w = []
        addr_strs = "{0:#0{1}x}".format(addr, 4)
        value_strs = "{0:#0{1}x}".format(value, 6)
        wr_cmd = ('wreg ' + addr_strs + ' ' + value_strs).encode()
        try:
            tx.write(wr_cmd)
        except:
            if logprint != None:
                logging.info("Writetmag: Error")
        else:
            # sleep(0.005) # allow all response from write arrive
            if logprint != None:
                for lineindex in range(3):
                    resp_w.append(reader.readline())
                print(resp_w)
            else:
                for lineindex in range(3):
                    reader.readline()
                return 0
    
    
    def readtmag(tx, reader, addr, logprint=None):
        addr_strs = "{0:#0{1}x}".format(addr, 4)
        rd_cmd = ('rreg ' + addr_strs).encode()
        if logprint != None:
            print(rd_cmd)
        try:
            tx.write(rd_cmd)
        except:
            if logprint != None:
                logging.info("Readtmag: Error")
        else:
            resp_r = reader.readline()  # 1st ack
            if logprint != None:
                print(resp_r)
            resp_r = reader.readline()  # 2nd val
            json_reg_data = json.loads(resp_r)
            if ('register' not in json_reg_data):
                raise Exception("no key in resp")
            resp_r = reader.readline()  # 3rd status
            return json_reg_data["register"]["value"]
    
    
    def readtmag_xyz(tx, reader, addr, logprint=None):
        addr_strs = "{0:#0{1}x}".format(addr, 4)
        rd_cmd = ('rreg ' + addr_strs).encode()
        if logprint != None:
            print(rd_cmd)
        try:
            tx.write(rd_cmd)
        except:
            if logprint != None:
                logging.info("Readtmag: Error")
        else:
            resp_r = reader.readline()  # 1st ack
            if logprint != None:
                print(resp_r)
            resp_r = reader.readline()  # 2nd val
            json_reg_data = json.loads(resp_r)
            if ('register' not in json_reg_data):
                raise Exception("no key in resp")
            resp_r = reader.readline()  # 3rd status
            if json_reg_data["register"]["value"] > 32768:  # means negative
                tmag_xyz = (-32768 + (json_reg_data["register"]["value"] - 32768))
            else:
                tmag_xyz = json_reg_data["register"]["value"]
            return tmag_xyz
    
    
    def animate(i, xs, ys, zs):
        if will_exit:
            print('sleep 2s')
            sleep(2)
            plt.close()
        else:
            plot_start_semaphore.acquire()
            xs.extend(x_val)
            ys.extend(y_val)
            zs.extend(z_val)
            sample_start_sem.release()
            logging.info("animate: sem post")
            # Limit y list to set number of items
            xs = xs[-t_len:]
            ys = ys[-t_len:]
            zs = zs[-t_len:]
    
            # Update line with new Y values
            lineax.set_ydata(xs)
            lineay.set_ydata(ys)
            lineaz.set_ydata(zs)
    
        return [lineax, lineay, lineaz]
    
    
    def plotter():
        # Create figure for plotting
        ax.set_ylim(y_range)
        ay.set_ylim(y_range)
        az.set_ylim(y_range)
    
        # Create a blank line. We will update the line in animate
    
        # Add labels
        plt.title('Hall Reading')
        plt.xlabel('Samples')
        plt.ylabel('Amp')
    
        # Set up plot to call animate() function periodically
        ani = animation.FuncAnimation(fig,
                                      animate,
                                      fargs=(xs, ys, zs),
                                      interval=200,  # 100ms
                                      blit=True)
        plt.show()
    
    def signal_handler(signum, frame):
        global will_exit
        will_exit = True
    
    def tmag_reader(serial):
        reader = ReadLine(serial)
        starttime_str = time.strftime("%Y%m%d_%H%M%S")
        starttime = time.time_ns()
        # try:
        while True:
            for runtime in range(50):
                tmag_x = readtmag_xyz(serial, reader, 0x09) * mtscale / 32768
                tmag_y = readtmag_xyz(serial, reader, 0x0A) * mtscale / 32768
                tmag_z = readtmag_xyz(serial, reader, 0x0B) * mtscale / 32768
                timestamp_nsval.append(time.time_ns() - starttime)
                x_val.append(tmag_x)
                y_val.append(tmag_y)
                z_val.append(tmag_z)
            # post a semaphore every 250 samples
            plot_start_semaphore.release()
            logging.info("sample: sem post")
            x_val_all.extend(x_val)
            y_val_all.extend(y_val)
            z_val_all.extend(z_val)
        ## generate a dictionary & save
            if will_exit:
                matdic = {"ts_ns": timestamp_nsval, "x_mt": x_val_all,
                            "y_mt": y_val_all, "z_mt": z_val_all}
                timestr = time.strftime("%Y%m%d_%H%M%S")
                filename = 'tmag_' + starttime_str + '-' + timestr + '.mat'
                # savemat(filename, matdic)
                print('[tmag_reader]: Saved mat file ('+ filename + ')')
                break
            sample_start_sem.acquire()
            x_val.clear()
            y_val.clear()
            z_val.clear()
        print('[tmag_reader]: Thread exit')
    
    if __name__ == "__main__":
        cnt_real = 0
        cnt = 0
        format = "%(asctime)s: %(message)s"
        logging.basicConfig(format=format, level=logging.INFO,
                            datefmt="%H:%M:%S")
    
        # Create figure for plotting
        ax.set_ylim(y_range)
        ay.set_ylim(y_range)
        az.set_ylim(z_range)
    
        # init setup
        num_of_line = 3
        tstart = time.time_ns()
        reader = ReadLine(s)
    
        # a. write 0x2000 to 0x00
        writetmag(s, reader, 0x00, 0x2000)
        reg_val = readtmag(s, reader, 0x00)
        if reg_val != 0x2000:
            raise Exception("error in 00")
    
        # b. write 0x25C0 to 0x01 (25mT / xyz / 1000ms sleep)
        writetmag(s, reader, 0x01, 0x25C0)
        reg_val = readtmag(s, reader, 0x01)
        if reg_val != 0x25C0:
            raise Exception("error in 01")
    
        # c. write 0x0200 to 0x02
        writetmag(s, reader, 0x02, 0x0200)
        reg_val = readtmag(s, reader, 0x02)
        if reg_val != 0x0200:
            raise Exception("error in 02")
    
        # d. write 0x0000 to 0x03
        writetmag(s, reader, 0x03, 0x0000)
        reg_val = readtmag(s, reader, 0x03)
        if reg_val != 0x0000:
            raise Exception("error in 03")
    
        # start conversion
        # e. write 0x2020 to 0x00
        writetmag(s, reader, 0x00, 0x2020)
        reg_val = readtmag(s, reader, 0x00)
    
        # add a signal handler for capturing Ctrl+C
        signal.signal(signal.SIGINT, signal_handler)
        signal.signal(signal.SIGTERM, signal_handler)
    
        if reg_val != 0x2020:
            raise Exception("error in 00")
        try:
            x = threading.Thread(target=tmag_reader, args=(s,))
            # x.daemon = True
            x.start()
        except:
            raise Exception('fail to create thread')
    
        # Create a blank line. We will update the line in animate
    
        # Add labels
        plt.title('Hall Reading')
        plt.xlabel('Samples')
        plt.ylabel('Amp')
    
        # Set up plot to call animate() function periodically
        ani = animation.FuncAnimation(fig,
                                    animate,
                                    fargs=(xs, ys, zs),
                                    interval=20,  # 100ms
                                    blit=True)
        plt.show()
        x.join()
        tstop = (time.time_ns() - tstart) / 1000000
    
        s.close()
        exit()

    谢谢、祝您顺利。

    套件

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    套件、

    根据您的代码、您似乎正在使用标准 USB 通信来实现读取。  遗憾的是、标准控制接口无法以传感器的最大采样率发送 SPI 事务。  在 EVM GUI 上、这种数据传输模式也会经历相同的延迟。  为了提高吞吐量、TI-SCB 能够实现大容量 USB 数据通信。  您需要设置 Python 代码、以便首先作为批量器件连接到 EVM。  

    本用户指南中提供了有关如何将此模式与 TI-SCB 搭配使用的更多指导:

    https://www.ti.com/lit/ug/sbou241d/sbou241d.pdf#page=20

    本用户指南中显示的标志反映了 INA228所需的内容。  对于 TMAG5170、这些标志定义如下:

    XAXIS       = 0b10000000;
    YAXIS       = 0b01000000;
    ZAXIS       = 0b00100000;
    温度        = 0b00010000;
    角度       = 0b00001000;
    幅度 = 0b00000100;

    此外、INA228支持以菊花链方式连接多个器件。  对于 TMAG5170、通道地址 ID 和 numDevices 应设置为1。

    数据将在必须解析的数据包中返回。  我已经了解了如何在已发布的 GUI 中完成此操作:

    	packetHandler: function (rxData) {
    
    				// Accumulate data
    				// CONSIDER: Checking if we are receiving more bytes than expected
    				//console.log(`${rxData.data.length} bytes comming in`);
    				rxData.data.forEach(byte => { 
    				    
    				    this.packetData[this.byteCount++] = byte; 
    				    
    				    if(this.byteCount > this.packetData.length)
    				    {
    				        console.error(this.is, `packetData overflow! (packet length: '${this.packetData.length}', byte count: '${this.byteCount}')`);
    				    }
    				    if(this.packetData.length === this.byteCount)
    				    {
    				        if(templateObj.$.ti_widget_checkbox_autoCollect.checked && numSamplesCollected >= templateObj.$.ti_widget_numberbox_samples_all.value)
    				        {
    				            this.fire('abort-collect');
    				        }
    				        else
    				        {
    				            this.dataParser();
    				        }
    				        this.byteCount = 0;
    				        numSamplesCollected++; 
    				    }
    				});
                    
    				// Debugging...
    				//console.log(rxData);
    			},
    
    			dataParser: function () {
    				let index = 0;
    				
    				//.log(`parsing data`);
    				
    				while (index < this.packetData.length) {
    
                        //Format: Frame ID, Address, Data
                        
    					// Check for frame ID and two data bytes
    					if (this.packetData[index] !== 0x00) {
    						console.error(this.is, `USB data misaligned - Cannot parse! (Index: '${index}', Value: '${this.packetData[index]}')`);
    						
    						this.fire('abort-collect');
    						index++; //needed?
    						return;
    					}
                        index++;
    				// 	let decimal = (this.packetData[index + 1] << 8) | this.packetData[index + 2];	// Unsigned
    				// 	if (!this.isADS1118) { decimal = this.signExtend(decimal >> 4, 12); }			// ADS1018 (ADC + Temp sensor): 12-bit left-aligned data
    				// 	else if (isTempMode) { decimal = this.signExtend(decimal >> 2, 14); }			// ADS1118 (Temp sensor): 14-bit left-aligned data
    				// 	else { decimal = this.signExtend(decimal, 16); }								// ADS1118 (ADC data):  16-bit data
    				// 	this.channelData.push(decimal);
    				// 	index += 3;
    				
        			
        				let Address = this.packetData[index++];
        				let Data = this.packetData[index++];
        				let RegisterSize = 2;//bytes
        				
    
        				
        				if (templateObj.$.ti_widget_checkbox_XAXIS.checked) //X
        				{
        				    CHX = 0;
        				    templateObj.$.ti_widget_scalargraph_MAGFIELD.series_0_label = "X-Component";
        				    templateObj.$.ti_widget_scalargraph_MAGFIELD.series_0_color = "#00BBCC"
        				    if (templateObj.$.ti_widget_checkbox_YAXIS.checked) //XY
        				    {
        				         CHY=1;
        				         templateObj.$.ti_widget_scalargraph_MAGFIELD.series_1_label = "Y-Component";
        				         templateObj.$.ti_widget_scalargraph_MAGFIELD.series_1_color = "#115566";
        				         if (templateObj.$.ti_widget_checkbox_ZAXIS.checked) //XYZ
        				         {
        				             CHZ=2;
        				             templateObj.$.ti_widget_scalargraph_MAGFIELD.series_2_label = "Z-Component";
        				             templateObj.$.ti_widget_scalargraph_MAGFIELD.series_2_color = "#AAAAAA";
        				         }
        				         else {CHZ = -1;}
        				    }
        				    else
        				    
        				    if (templateObj.$.ti_widget_checkbox_ZAXIS.checked) //XZ
        				    {
        				        CHY=-1;
        				        CHZ=1;
        				        templateObj.$.ti_widget_scalargraph_MAGFIELD.series_1_label = "Z-Component";
        				        templateObj.$.ti_widget_scalargraph_MAGFIELD.series_1_color = "#AAAAAA";
        				    }
        				    else //X only
        				    {
        				        CHY=-1;
        				        CHZ=-1;
        				    }
        				}
        				
        				else //No X
        				{
        				    CHX = -1;
        				    if (templateObj.$.ti_widget_checkbox_YAXIS.checked) 
        				    {
        				        CHY = 0;
        				        templateObj.$.ti_widget_scalargraph_MAGFIELD.series_0_label = "Y-Component";
        				        templateObj.$.ti_widget_scalargraph_MAGFIELD.series_0_color = "#115566";
        				        if (templateObj.$.ti_widget_checkbox_ZAXIS.checked) 
        				        {
        				            CHZ=1;
        				            templateObj.$.ti_widget_scalargraph_MAGFIELD.series_1_label = "Z-Component";
        				            templateObj.$.ti_widget_scalargraph_MAGFIELD.series_1_color = "#AAAAAA";
        				        }
        				        else {CHZ = -1;}
        				    }
        				    else
        				    {
        				        CHY = -1;
        				        if (templateObj.$.ti_widget_checkbox_ZAXIS.checked) 
        				        {
        				            CHZ = 0;
        				            templateObj.$.ti_widget_scalargraph_MAGFIELD.series_0_label = "Z-Component";
        				             templateObj.$.ti_widget_scalargraph_MAGFIELD.series_0_color = "#AAAAAA";
        				        }
        				        else {CHZ=-1;}
        				        
        				    }
        				}
        				
        				for(let i = 1; i < RegisterSize; i++)
        				{
        				    Data = (Data << 8) | this.packetData[index++];
        				}
        				let temp = Data;
        				
        			
                      
        				
        				if(Address === 0x9 || Address === 0xA || Address === 0xB) //X,Y,Z
        				{
    
    				         if(Data >= 0x7FFF)
    				        {
    				        	Data = Data - 0x10000;
    				        }
    				        
    				        let maxVal = 32767;
                            let minVal = -32768;
                            if(Data > maxVal) {Data = -Data/minVal;}
                            else{Data = Data/maxVal;}
    				       
    				        let ChannelID;
                            if (Address === 0x09) 
                            {
                                ChannelID = CHX;
                                Data = Data * adcrange[0];
                            }
                            else if (Address === 0x0A)
                            { 
                                ChannelID = CHY;
                                 Data = Data * adcrange[1];
                            }
                            else if (Address === 0x0B)
                            { 
                                ChannelID = CHZ;
                                Data = Data * adcrange[2];
                            }
    				        //put data into plot
                            if(templateObj.$.ti_widget_scalargraph_MAGFIELD[`value_${ChannelID}`] === Data)
                            {
                                if(ChannelID === 0)
                                {
                                    templateObj.$.ti_widget_scalargraph_MAGFIELD.value_0Changed();
                                }
                                else if(ChannelID === 1)
                                {
                                    templateObj.$.ti_widget_scalargraph_MAGFIELD.value_1Changed();
                                }
                                else if(ChannelID === 2)
                                {
                                    templateObj.$.ti_widget_scalargraph_MAGFIELD.value_2Changed();
                                }
                            }
                            else
                            {
                                templateObj.$.ti_widget_scalargraph_MAGFIELD[`value_${ChannelID}`] = Data;
                            }
                            
        				}
    				   else if(Address === 0xC) //DIE TEMP
    				    {
    				        //Data = 65/256*(Data/16-1066)+25;
    				        let T0 = 25;//Ref temp
    				        let ADCT0 = 17522;//ADC value at T0
    				        let TRES = 60; //LSB per C
    				        
    				        Data = T0 + (Data-ADCT0)/TRES;
    				         //optionally convert to F
    				        if(ti_widget_droplist_dietemp_unit.selectedText == "°F")
    				        {
    				            Data = (Data * (9/5)) + 32;
    				        }
    				       
                             if(templateObj.$.ti_widget_scalargraph_DIETEMP.value_0 === Data)
                            {
    				        templateObj.$.ti_widget_scalargraph_DIETEMP.value_0Changed();
        			        }
        			         else
                            {
                                templateObj.$.ti_widget_scalargraph_DIETEMP.value_0 = Data;
                            }
    				    }    			
    				    else if(Address === 0x13) //ANGLE
    				    {
    				        let fraction = Data & 0xF;
    				        Data = Data >> 4;
    				        Data = Data + fraction/16;
    				       
    				        if(templateObj.$.ti_widget_scalargraph_ANGLE.value_0 === Data)
                            {
                            	templateObj.$.ti_widget_scalargraph_ANGLE.value_0Changed();
                            }
                            else
                            {
                                templateObj.$.ti_widget_scalargraph_ANGLE.value_0 = Data;
                            }
                           
    				    }
    				    else if(Address === 0x14) //Magnitude
    				    {
    				        let result = Data;
                            let maxVal = 32767; //use xyz chanel max val, for scale
                            
                           	let mRange;
        				
                            if('ti_model_register.sensor_config_register.angle_en' == 2 )
                            {
                                mRange = adcrange[1];
                            }
                            else 
                            {
                                mRange = adcrange[0];
                            }
                
                            Data = 16*Data*mRange/maxVal; //multiply by 16 for magnitude conversion (from 12 bit xyz chanel values)
                            if(templateObj.$.ti_widget_scalargraph_MAGNITUDE.value_0 === Data)
                            {
                            	templateObj.$.ti_widget_scalargraph_MAGNITUDE.value_0Changed();
                            }
                            else
                            {
                                templateObj.$.ti_widget_scalargraph_MAGNITUDE.value_0 = Data;
                            }
    				    }
    				   
    				// Debugging...
    				//console.log(this.channelData);
    			}},

    希望这能帮助您整理连接、以便能够以最大速率收集数据。

    谢谢、

    Scott

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Scott、

    是的、您回答正确。 原因这是 EVM 指南 sbau388a.pdf 所暗示的唯一模式。 也许应该将批量模式添加到指南中。

    我将仔细检查并尝试您提供的资源/示例。 如果遇到任何其他问题、我将提出一个新问题。

    谢谢、祝您顺利。

    套件