This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

SPI with LS7366R

Hi

I'm working with an nrf52840-dk on NCS 1.8.0.

I'm attempting to interface the board with an LS7366R quadrature counter over SPI; however, I'm not receiving any count information when it is requested.  I'm an auditor, not an engineer, so I may be interpreting the data sheet incorrectly, so I was hoping I could get a sanity check on the test code I threw together to see if there is anything obviously with my configuration. Everything is hardcoded at the moment.

The data sheet for the IC is here -  https://lsicsi.com/datasheets/LS7366R.pdf - and is fairly straight forward as to how it operates, or at least I thought.

Specifically, though, I'm using the breakout here: www.superdroidrobots.com/.../product=2397

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <zephyr.h>
#include <logging/log.h>

#include <drivers/spi.h>

#define CLR_CNTR 0x20
#define READ_MDR0 0x48
#define READ_MDR1 0x50
#define READ_CNTR 0x60 
#define WRITE_MDR0 0x88
#define COUNTER_4X_QUAD 0x03    

LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);

struct spi_cs_control spi_cs = {
	.gpio_pin = DT_GPIO_PIN_BY_IDX(DT_NODELABEL(spi1), cs_gpios, 0),
	.gpio_dt_flags = GPIO_ACTIVE_LOW,
	.delay = 0,
};

static struct spi_config spi_cfg = {
	.operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_LINES_SINGLE | SPI_WORD_SET(8),
	.frequency = 2000000,
	.slave = 0,
	.cs = &spi_cs,
};

const struct device *spi_dev;


void spiInit(void)
{
	LOG_INF("Initializing SPI 1\n");

	const char* const spiName = "SPI_1";
	spi_cs.gpio_dev = device_get_binding("GPIO_1");
	if (spi_cs.gpio_dev == NULL) 
	{
	    LOG_ERR("Couldn't get GPIO_1 device\n");
	}

	spi_dev = device_get_binding(spiName);

	if (spi_dev == NULL) {
		LOG_ERR("Couldn't get %s device\n", spiName);
		return;
	}
    LOG_INF("SPI 1 Initialized\n");
}

void setMDRO(void)
{ 
	//MDRO is always a one byte register.  Expects 1 byte of data (i.e., settings).  Second tx byte for command.
	int err;
	static uint8_t tx_buffer[2];
	
	const struct spi_buf tx_buff = {
		.buf = tx_buffer,
		.len = sizeof(tx_buffer)
	};

	const struct spi_buf_set tx = {
		.buffers = &tx_buff,
		.count = 1
	};

	tx_buffer[0] = WRITE_MDR0;
	tx_buffer[1] = COUNTER_4X_QUAD;  //other default settings on register are fine

	err = spi_write(spi_dev, &spi_cfg, &tx);
	if(err)
	{
		LOG_ERR("Failed to set MDR0: %d\n", err);
	} else
	{
		LOG_INF("MDR0 is setup\n");
	}
}

void readMDRO(void)
{ 
	int err;
	static uint8_t tx_buffer[1];

	const struct spi_buf tx_buff = {
		.buf = tx_buffer,
		.len = sizeof(tx_buffer)
	};

	const struct spi_buf_set tx = {
		.buffers = &tx_buff,
		.count = 1
	};

	static uint8_t rx_buffer[1];

	const struct spi_buf rx_buff = {
		.buf = rx_buffer,
		.len = sizeof(rx_buffer)
	};

	const struct spi_buf_set rx = {
		.buffers = &rx_buff,
		.count = 1
	};

	tx_buffer[0] = READ_MDR0;

	err = spi_transceive(spi_dev, &spi_cfg, &tx, &rx);
	if(err)
	{
		LOG_ERR("Read MDR0 Failed): %d\n", err);
	} else
	{
		LOG_INF("Read MDR0\n");
	}
}

void readCounter(void)
{
int err;
	static uint8_t tx_buffer[1];
	LOG_INF("sizeof(tx_buffer) = %i", sizeof(tx_buffer));

	const struct spi_buf tx_buff = {
		.buf = tx_buffer,
		.len = sizeof(tx_buffer)
	};

	const struct spi_buf_set tx = {
		.buffers = &tx_buff,
		.count = 1
	};

	//counter hardcoded at 32 bits via MDR1 default settings, should get 4 bytes of data back
	static uint8_t rx_buffer[4];

	const struct spi_buf rx_buff = {
		.buf = rx_buffer,
		.len = sizeof(rx_buffer)
	};

	const struct spi_buf_set rx = {
		.buffers = &rx_buff,
		.count = 1
	};

	tx_buffer[0] = READ_CNTR;

	err = spi_transceive(spi_dev, &spi_cfg, &tx, &rx);
	if(err)
	{
		LOG_ERR("Read Counter Failed): %d\n", err);
	} else
	{
		LOG_INF("Read Counter\n");
	}
}

void main(void)
{
	spiInit();
	setMDRO();
	readMDRO(); //no error, but no information provided either.
	while (1) 
		{
			readCounter(); //no error, but no information provided either.
			printk("\r\n");
			k_sleep(K_MSEC(4000));
		}
}

// void setMDR1(void)
// {
// 	/* Register goes to 0 at powercycle (i.e., using default settings: four byte counter, counter enabled)*/
// }

// void setDTR(void);
// {
	// NA for these hardcoded settings
	// DTR bytes vary by counter byte setting:  32 bit mode -> 32 bit register
// }

// void clearSTR(void)
// {
		/*clears on powercycle */
// }

I'm not receiving any errors when reading the registers, but I'm also not getting back any information.  For example, when requesting the counter value (0x60), I see the following:

The image also shows the MDR0 read attempt (0x48) on the right.  Essentially, I'm not seeing any movement on the MISO, which makes me think I'm not interpreting something correctly in the Zephyr docs.

/* nrf52840dk_nrf52840.overlay */
/ {
	chosen {
		zephyr,entropy = &rng;
	};
};
&spi3 {
	compatible = "nordic,nrf-spim";
	status = "disabled";
};
&spi1 {
	compatible = "nordic,nrf-spim";
	status = "okay";
	cs-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>; //p1.12
	sck-pin = <47>;							// p1.15
	miso-pin = <46>;  						// p1.14
	mosi-pin = <45>; 						// p1.13
};

/* pjr.conf */
CONFIG_SPI=y
CONFIG_LOG=y
CONFIG_SERIAL=y

Thanks

  • Hello,

    Are you powering the board through J-Link USB, or VDDH?

  • Hi.  I'm powering on J2, J-link USB.

  • To update, I did get this working.  

    I moved away from "standard drive" GPIOs (which I don't believe made a difference, as it seems using those at frequencies above 10kHz isn't a limitation, but rather, a recommendation due to potential radio interference), but more importantly, I reduced the SPI frequency from the attempted 2MHz down to the minimum 125kHz and worked my way up.  I did move from SPI1 to SPI3, but I think that only makes a difference if you're looking for SPI frequencies greater than 8MHz (i.e., I was just trying different things).

    This leads to my follow-up question:  

    The counter reads/writes over the bus without issue if I compile with a SPI frequency of 1.99MHz or less.  If I attempt 2MHz or greater, the LS7366r stops responding to my count calls (assumedly my writes to the configuration registers don't take either) just as it did in my main post above.

    Obviously this sounds like a limitation of the counter, but I slapped together an app on esp-idf that had no trouble at 2-4MHz, and the breadboards manufacturer's Arduino library for the chip runs at 4MHz without issue.  The manufacturer also states that the breadboard the LS7366r is on can handle 20MHz due to the particular oscillator they mounted (the IC itself can go up to 40MHz when powered via 5v).  

    Is there a limitation with Zephyr regarding the SPI frequency or, again, something screwy with my configure?  I read the nrf52840 isn't supported by Nordic re: Zephyr.  Is that true?  If so, I can close this ticket and stop hassling everyone.

  • Perhaps you can try setting all the pins to high drive (SCK/MISO/MOSI). Also, you can consider doing a logic trace when using 2MHz or greater frequency, to see what it looks like.

  • Thanks Hakon.

    I see Zephyr GPIO documentation related to pin voltage flags - nothing about pin amperes or high-drive specifically .  Is there a standard method for setting SPI pins to high drive through zephyr APIs/device tree configs given nrf_gpio_cfg is not available with my current approach?  

Related