Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ade7913 driver improvements #510

Merged
merged 4 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 69 additions & 9 deletions adc/ade7913/ade7913-driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
#define log_error(fmt, ...) do { printf(LOG_TAG COL_RED fmt COL_NORMAL "\n", ##__VA_ARGS__); } while (0)
/* clang-format on */

/* enable debugging of DMA IRQ not in-sync processing */
#define DEBUG_NOTSYNC 1
agkaminski marked this conversation as resolved.
Show resolved Hide resolved

#ifndef ADE7913_DREADY_MUXPIN
#define ADE7913_DREADY_MUXPIN pctl_mux_gpio_ad_21
Expand Down Expand Up @@ -84,12 +86,16 @@
#endif

/*
* The buffer needs to be aligned with:
* num_of_devices * bytes_per_device * num_of_buffers
* Single buffer needs to be aligned with:
* num_of_devices * bytes_per_device
* so that in each filled buffer there will be same amount
* of samples for each device.
*
* Single buffer len can't exceed 0x200 * sizeof(uint32_t) = 2048
* (SPI_RCV TCD `biter_elinkyes` can hold only 9-bit minor loop cnt)
*/
#define ADC_BUFFER_SIZE (4 * (ADE7913_BUF_NUM) * _PAGE_SIZE)
#define ADC_BUFFER_SIZE (1920 * (ADE7913_BUF_NUM))
_Static_assert((ADC_BUFFER_SIZE / ADE7913_BUF_NUM) <= (0x200 * sizeof(uint64_t)), "Single buffer size too large for SPI_RCV TCD");

#define DREADY_DMA_CHANNEL 5
#define SPI_RCV_DMA_CHANNEL 6
Expand Down Expand Up @@ -127,8 +133,13 @@ static const int spi_clk[] = { pctl_clk_lpspi1, pctl_clk_lpspi2, pctl_clk_lpspi3


/* ADE7913 commands LUT used by DMA */
/* `04` triggers SPI read in Burst Mode, we need to keep SCLK running for next 14 bytes, (000000) would trigger ADE reset */
static const uint32_t adc_read_cmd_lookup[4] = { 0xFFFFFF04, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };

_Static_assert(((ADC_BUFFER_SIZE / ADE7913_BUF_NUM) % (4 * sizeof(adc_read_cmd_lookup)) == 0), "Buffer size won't support 4 devices");
_Static_assert(((ADC_BUFFER_SIZE / ADE7913_BUF_NUM) % (3 * sizeof(adc_read_cmd_lookup)) == 0), "Buffer size won't support 3 devices");
/* divisible by 2 and 1 from the checks above */

static uint32_t spi_write_cmd_lookup[4] = {
((uint32_t)spi_mode_3 << 30) | (1 << 27) | (0 << 24) | (spi_msb << 23) | (1 << 22) | (16 * 8 - 1),
((uint32_t)spi_mode_3 << 30) | (1 << 27) | (1 << 24) | (spi_msb << 23) | (1 << 22) | (16 * 8 - 1),
Expand Down Expand Up @@ -162,12 +173,21 @@ struct {
oid_t oid;

int enabled;

#if DEBUG_NOTSYNC
volatile uint32_t edma_error;
volatile uint32_t notsync;
volatile uint32_t prev_transfers;
volatile uint32_t tcd_daddr;
#endif /* DEBUG_NOTSYNC */
} common;


static int edma_spi_rcv_irq_handler(unsigned int n, void *arg)
{
#if DEBUG_NOTSYNC
struct edma_tcd_s tcd;
#endif /* DEBUG_NOTSYNC */
uint32_t reg, mux_copy[4];
int i, notsync = 0;

Expand Down Expand Up @@ -211,22 +231,33 @@ static int edma_spi_rcv_irq_handler(unsigned int n, void *arg)
*common.iomux_ptr[i] = mux_copy[i];
}

#if 0 /* not needed in normal use case, for now keeping code until testing would be finished */
/* Re-enable /DREADY after SYNC broadcast */
edma_install_tcd(common.tcd_dready_ptr, DREADY_DMA_CHANNEL);
edma_channel_enable(DREADY_DMA_CHANNEL);
#endif

if (notsync == 0) {
++common.edma_transfers;
}
else {
#if DEBUG_NOTSYNC
/* NOTE: the notsync event happens on second IRQ handler after boot-up - the reason is unknown,
* after TCD adjustment everything works as expected */
common.notsync = 1;
common.prev_transfers = common.edma_transfers;
edma_read_tcd(&tcd, SPI_RCV_DMA_CHANNEL);
common.tcd_daddr = tcd.daddr;
#endif /* DEBUG_NOTSYNC */

/* If not in-sync adjust DMA TCD (as described above) */
edma_install_tcd(common.tcd_spircv_ptr, SPI_RCV_DMA_CHANNEL);
edma_channel_enable(SPI_RCV_DMA_CHANNEL);
edma_read_tcd(&tcd, SPI_RCV_DMA_CHANNEL);

/* adjust edma_transfers to be monotonic and point to next buf_num `0` */
/* WARN: if ADE7913_BUF_NUM is not a power of 2, change second line to edma_transfers -= edma_transfers % ADE7913_BUF_NUM */
common.edma_transfers += ADE7913_BUF_NUM;
common.edma_transfers &= ~(ADE7913_BUF_NUM - 1);
common.edma_transfers += ((((tcd.daddr + tcd.doff) - (uint32_t)common.buff) & ~(ADC_BUFFER_SIZE / (ADE7913_BUF_NUM) - 1)) >> 11);
}

edma_clear_interrupt(SPI_RCV_DMA_CHANNEL);
Expand All @@ -241,6 +272,10 @@ static int edma_error_handler(unsigned int n, void *arg)

if (edma_error_channel() & mask) {
edma_clear_error(DREADY_DMA_CHANNEL);
edma_channel_enable(DREADY_DMA_CHANNEL);
#if DEBUG_NOTSYNC
common.edma_error = 1;
#endif /* DEBUG_NOTSYNC */
}

return EOK;
Expand Down Expand Up @@ -438,7 +473,7 @@ static int adc_init(int hard)
devnum = (int)(common.order[i] - '0');

if (ade7913_reset_hard(&common.ade7913_spi, devnum) < 0) {
log_error("Could reset ADE7913 no. %d", devnum);
log_error("Could not reset ADE7913 no. %d", devnum);
}
}

Expand Down Expand Up @@ -533,6 +568,7 @@ static int dma_setup_tcds(void)
{
int cs_seq, res, i, tcd_count;

/* DREADY_DMA_CHANNEL */
common.tcds[0].soff = 0;
common.tcds[0].attr = (edma_get_tcd_attr_xsize(sizeof(uint32_t)) << 8) |
edma_get_tcd_attr_xsize(sizeof(uint32_t));
Expand All @@ -554,13 +590,15 @@ static int dma_setup_tcds(void)
/* Enable scatter-gather and link with SPI send channel at major loop end */
common.tcds[0].csr = TCD_CSR_ESG_BIT | TCD_CSR_MAJORLINK_CH(SPI_SND_DMA_CHANNEL);

/* SPI_SND_DMA_CHANNEL */
/* SPI BULK readout command TCD (the same for every ADE) */
common.tcds[4].soff = sizeof(uint32_t);
common.tcds[4].attr = (edma_get_tcd_attr_xsize(sizeof(uint32_t)) << 8) |
edma_get_tcd_attr_xsize(sizeof(uint32_t));

/* Number of bytes per minor loop iteration */
common.tcds[4].nbytes_mlnoffno = 4 * sizeof(uint32_t);
common.tcds[4].slast = -sizeof(uint32_t);
common.tcds[4].slast = -common.tcds[4].nbytes_mlnoffno;
common.tcds[4].doff = 0;
common.tcds[4].dlast_sga = (uint32_t)&common.tcds[4];

Expand All @@ -575,7 +613,7 @@ static int dma_setup_tcds(void)
/* Enable scatter-gather */
common.tcds[4].csr = TCD_CSR_ESG_BIT;

/* Clone the above setup for each of the ADE7913 devices creating a ring */
/* Clone the above setup (SPI setup with consecutive CS enable command) for each of the ADE7913 devices creating a ring */
for (i = 1; i < common.devcnt; ++i) {
edma_copy_tcd(&common.tcds[i], &common.tcds[0]);
common.tcds[i].dlast_sga = (uint32_t)(&common.tcds[i + 1]);
Expand All @@ -585,6 +623,7 @@ static int dma_setup_tcds(void)
/* ... and close the ring */
common.tcds[common.devcnt - 1].dlast_sga = (uint32_t)(&common.tcds[0]);

/* SPI_RCV_DMA_CHANNEL */
/* Setup SPI receive buffers (for samples) */
common.tcds[5].soff = 0;
common.tcds[5].saddr = (uint32_t)(common.spi_ptr + spi_rdr);
Expand Down Expand Up @@ -621,10 +660,19 @@ static int dma_setup_tcds(void)
* !STOP -! SEQ_DMA_CHANNEL
* (devcnt=4, three-phase meter L1,L2,L3,N)
*
* 1. DREADY_DMA_CHANNEL configures SPI (enables CSx) and triggers SPI_SND channel
* 2. SPI_SND_CHANNEL sends 4 * 4 bytes via SPI (Bulk readout channel)
* 3. Every minor loop iteration (4 bytes) the SPI_RCV channel can be triggered (by SPI peripheral)
* 4. After every minor loop iteration of SPI_RCV channel (4 bytes received) trigger SEQ_DMA_CHANNEL
* 5. Every 4th SEQ_DMA_CHANNEL trigger (4 * 4 bytes received) will trigger DREADY_DMA_CHANNEL (move to next CS)
*
* 6. SPI_RCV_CHANNEL: every time (ADC_BUFFER_SIZE / ADE7913_BUF_NUM) bytes are read (major loop iteration) - trigger interrupt and to ADC SYNC in IRQ
*
*/

cs_seq = 5 + i;

/* SEQ_RMA_CHANNEL */
common.tcds[cs_seq].soff = 0;
common.tcds[cs_seq].saddr = 0;
common.tcds[cs_seq].slast = 0;
Expand Down Expand Up @@ -851,6 +899,18 @@ static int dev_read(void *data, size_t size)
}
mutexUnlock(common.edma_spi_rcv_lock);

#if DEBUG_NOTSYNC
if (common.notsync != 0) {
common.notsync = 0;
uint32_t diff = (common.tcd_daddr) - (uint32_t)common.buff;
log_info("notsync: %u -> %u (daddr(0x%x) - buff(0x%x) = 0x%x)", common.prev_transfers, common.edma_transfers, common.tcd_daddr, (uint32_t)common.buff, diff);
}
if (common.edma_error != 0) {
common.edma_error = 0;
log_info("edma error detected (transfers: %u)", common.edma_transfers);
}
#endif /* DEBUG_NOTSYNC */

return res;
}

Expand Down Expand Up @@ -1092,7 +1152,7 @@ int main(int argc, char **argv)

for (i = 0; i < common.devcnt; ++i) {
devnum = common.order[i] - '0';
if (devnum >= common.devcnt || devnum < 0) {
if (devnum >= 4 || devnum < 0) {
log_error("Wrong order format provided");
usage(argv[0]);
return EXIT_FAILURE;
Expand Down
7 changes: 3 additions & 4 deletions adc/ade7913/ade7913.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,9 @@ int ade7913_sync(oid_t *device, const char *cs, int devcnt, int snap)
oid_t gpiodev;
platformctl_t pctl;

int muxes[4] = { pctl_mux_gpio_ad_18, pctl_mux_gpio_ad_19,
pctl_mux_gpio_ad_20, pctl_mux_gpio_ad_29 };
int muxes[4] = { pctl_mux_gpio_ad_29, pctl_mux_gpio_ad_18, pctl_mux_gpio_ad_19, pctl_mux_gpio_ad_20 };

int pins[4] = { 17, 18, 19, 28 };
int pins[4] = { 28, 17, 18, 19 };
agkaminski marked this conversation as resolved.
Show resolved Hide resolved

uint8_t buff[2] = { (ade7913_sync_snap << ADE7913_ADDR_OFFS), ADE7913_SYNC_SNAP_SYNC };

Expand Down Expand Up @@ -289,7 +288,7 @@ int ade7913_sync(oid_t *device, const char *cs, int devcnt, int snap)
pctl.iomux.sion = 0;
pctl.iomux.mode = 5;

for (i = 0; i < 4; ++i) {
for (i = 0; i < devcnt; ++i) {
pctl.iomux.mux = muxes[(int)(cs[i] - '0')];
platformctl(&pctl);
}
Expand Down
8 changes: 4 additions & 4 deletions dma/imxrt-edma/imxrt-edma.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,22 +298,22 @@ int edma_is_hw_req_pending(unsigned channel)

void edma_channel_enable(unsigned channel)
{
edma_regs->serq = channel | (1 << 6);
edma_regs->serq = channel;
}

void edma_channel_disable(unsigned channel)
{
edma_regs->cerq |= channel;
edma_regs->cerq = channel;
}

void edma_clear_interrupt(unsigned channel)
{
edma_regs->cint |= channel;
edma_regs->cint = channel;
}

void edma_clear_error(unsigned channel)
{
edma_regs->cerr |= channel;
edma_regs->cerr = channel;
}

void edma_software_request_start(int channel)
Expand Down
Loading