mirror of
git://projects.qi-hardware.com/ben-blinkenlights.git
synced 2024-11-05 03:05:19 +02:00
ubb-la/: data capture via UBB and MSC+DMA (WIP)
This commit is contained in:
parent
d4c1f5666c
commit
2c5b3625a7
34
ubb-la/Makefile
Normal file
34
ubb-la/Makefile
Normal file
@ -0,0 +1,34 @@
|
||||
#
|
||||
# ubb-la/Makefile - Build the UBB logic analyzer
|
||||
#
|
||||
# Written 2013 by Werner Almesberger
|
||||
# Copyright 2013 Werner Almesberger
|
||||
#
|
||||
# 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, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
|
||||
CC = mipsel-openwrt-linux-gcc
|
||||
CFLAGS = -g -Wall -O9 -I../libubb/include
|
||||
LDFLAGS =
|
||||
LDLIBS = -L../libubb -lubb -lm -lrt
|
||||
|
||||
MAIN = ubb-la
|
||||
OBJS = ubb-la.o
|
||||
|
||||
.PHONY: all static clean spotless
|
||||
|
||||
all: $(MAIN)
|
||||
|
||||
static:
|
||||
$(MAKE) LDFLAGS=-static
|
||||
|
||||
$(MAIN): $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS)
|
||||
|
||||
spotless: clean
|
||||
rm -f $(MAIN)
|
232
ubb-la/ubb-la.c
Normal file
232
ubb-la/ubb-la.c
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* ubb-la.c - UBB logic analyzer
|
||||
*
|
||||
* Written 2013 by Werner Almesberger
|
||||
* Copyright 2013 Werner Almesberger
|
||||
*
|
||||
* 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, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <ubb/ubb.h>
|
||||
#include <ubb/regs4740.h>
|
||||
#include <ubb/mmcclk.h>
|
||||
#include <ubb/physmem.h>
|
||||
|
||||
|
||||
#define DMA 5
|
||||
|
||||
|
||||
/* ----- Enable/disable interrupts ----------------------------------------- */
|
||||
|
||||
|
||||
static uint32_t old_icmr;
|
||||
|
||||
|
||||
static void disable_interrupts(void)
|
||||
{
|
||||
old_icmr = ICMR;
|
||||
ICMSR = 0xffffffff;
|
||||
}
|
||||
|
||||
|
||||
static void enable_interrupts(void)
|
||||
{
|
||||
ICMCR = ~old_icmr;
|
||||
}
|
||||
|
||||
|
||||
/* ----- DMA control ------------------------------------------------------- */
|
||||
|
||||
|
||||
static uint32_t old_dmac;
|
||||
|
||||
|
||||
static void dma_stop(void)
|
||||
{
|
||||
DCS(DMA) =
|
||||
DCS_TT | /* Transfer terminated */
|
||||
DCS_HLT; /* DMA halt */
|
||||
DCS(DMA) = 0; /* reset DMA channel */
|
||||
}
|
||||
|
||||
|
||||
static void dma_init(void)
|
||||
{
|
||||
old_dmac = DMAC;
|
||||
|
||||
DMAC = DMAC_DMAE; /* activate the DMA controller (in case it's off) */
|
||||
dma_stop();
|
||||
|
||||
DCM(DMA) =
|
||||
DCM_DAI | /* destination address increment */
|
||||
(DCM_TSZ_32BYTE << DCM_TSZ_SHIFT);
|
||||
/* transfer size is 32 bytes */
|
||||
DRT(DMA) = DRT_MSC_RX; /* MSC receive-fifo-full transfer request */
|
||||
}
|
||||
|
||||
|
||||
static void dma_cleanup(void)
|
||||
{
|
||||
DMAC = old_dmac;
|
||||
dma_stop();
|
||||
}
|
||||
|
||||
|
||||
static void dma_setup(unsigned long buf, int nibbles)
|
||||
{
|
||||
assert(!(nibbles & 63));
|
||||
|
||||
DCS(DMA) = DCS_NDES; /* no-descriptor transfer */
|
||||
DSA(DMA) = REG_PADDR(MSC_RXFIFO); /* source */
|
||||
DTA(DMA) = buf; /* destination */
|
||||
DTC(DMA) = nibbles >> 6; /* 32 bytes per transfer */
|
||||
}
|
||||
|
||||
|
||||
static void wait_dma_done(void)
|
||||
{
|
||||
while (!(DCS(DMA) & DCS_TT));
|
||||
}
|
||||
|
||||
|
||||
/* ----- MMC control ------------------------------------------------------- */
|
||||
|
||||
|
||||
static void xfer(unsigned long buf, int nibbles)
|
||||
{
|
||||
dma_init();
|
||||
dma_setup(buf, nibbles);
|
||||
|
||||
MSC_STRPCL = MSC_STRPCRL_START_CLOCK; /* start the bus clock */
|
||||
MSC_RESTO = MSC_RESTO_MASK; /* maximum response time-out */
|
||||
MSC_RDTO = MSC_RDTO_MASK;
|
||||
MSC_BLKLEN = nibbles >> 1;
|
||||
|
||||
MSC_CMDAT =
|
||||
MSC_CMDAT_BUS_WIDTH_4 << MSC_CMDAT_BUS_WIDTH_SHIFT |
|
||||
MSC_CMDAT_DMA_EN | /* DMA */
|
||||
MSC_CMDAT_DATA_EN | /* with data transfer */
|
||||
MSC_CMDAT_RESPONSE_FORMAT_NONE; /* no response required */
|
||||
|
||||
MSC_STRPCL = MSC_STRPCRL_START_OP;
|
||||
|
||||
while (MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY);
|
||||
|
||||
IN(UBB_CMD);
|
||||
|
||||
disable_interrupts();
|
||||
|
||||
while (!(PDPIN & UBB_DAT1));
|
||||
|
||||
// sleep(1); /* @@@ wait here for trigger */
|
||||
|
||||
DCS(DMA) =
|
||||
DCS_NDES | /* no descriptor */
|
||||
DCS_CTE; /* enable channel */
|
||||
|
||||
enable_interrupts();
|
||||
|
||||
wait_dma_done();
|
||||
|
||||
printf("MSC_STAT = %08x\n", MSC_STAT);
|
||||
|
||||
dma_cleanup();
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void do_buf(int nibbles)
|
||||
{
|
||||
uint8_t *buf = physmem_malloc(4095);
|
||||
struct physmem_vec vec;
|
||||
int n, i;
|
||||
uint8_t v, last = 0xff;
|
||||
int count = 0;
|
||||
|
||||
if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
|
||||
perror("mlockall");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(buf, 0, 4095);
|
||||
physmem_flush(buf, 4095);
|
||||
|
||||
n = physmem_xlat((void *) buf, nibbles >> 1, &vec, 1);
|
||||
if (n != 1) {
|
||||
fprintf(stderr, "physmem_xlat_vec: expected 1, got %d\n", n);
|
||||
exit(1);
|
||||
}
|
||||
xfer(vec.addr, nibbles);
|
||||
|
||||
for (i = 0; i != nibbles; i++) {
|
||||
v = (buf[i >> 1] >> (4*(~i & 1))) & 0xf;
|
||||
if (v == last) {
|
||||
count++;
|
||||
} else {
|
||||
switch (count) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
printf("%X", last);
|
||||
break;
|
||||
default:
|
||||
printf("%X{%d}", last, count);
|
||||
break;
|
||||
}
|
||||
last = v;
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
if (count == 1)
|
||||
printf("%X\n", last);
|
||||
else
|
||||
printf("%X{%d}\n", last, count);
|
||||
}
|
||||
|
||||
|
||||
static void frequency(struct mmcclk *clk, int hz)
|
||||
{
|
||||
struct mmcclk mmc;
|
||||
|
||||
mmcclk_first(&mmc, 0);
|
||||
*clk = mmc;
|
||||
while (mmcclk_next(&mmc))
|
||||
if (fabs(clk->bus_clk_hz-hz) > fabs(mmc.bus_clk_hz-hz))
|
||||
*clk = mmc;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct mmcclk clk;
|
||||
|
||||
ubb_open(UBB_ALL);
|
||||
PDFUNS = UBB_DAT0 | UBB_DAT1 | UBB_DAT2 | UBB_DAT3;
|
||||
PDFUNS = UBB_CLK;
|
||||
OUT(UBB_CMD);
|
||||
CLR(UBB_CMD);
|
||||
PDFUNC = UBB_CMD;
|
||||
|
||||
frequency(&clk, atoi(argv[1]));
|
||||
printf("bus %g MHz (MSC %g MHz)\n", clk.bus_clk_hz/1e6,
|
||||
clk.sys_clk_hz/(clk.clkdiv+1.0)/1e6);
|
||||
mmcclk_start(&clk);
|
||||
|
||||
do_buf(6400);
|
||||
|
||||
mmcclk_stop();
|
||||
ubb_close(UBB_ALL);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user