aboutsummaryrefslogtreecommitdiffstats
path: root/sam
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2019-12-21 16:46:53 +0100
committerHarald Welte <laforge@osmocom.org>2019-12-21 16:46:53 +0100
commitc590c19cc6cd8bd020f56faff70b15603be81935 (patch)
treed0b96da86b59084cdcd750b97be84bd5591f71d3 /sam
parent1bd94ad07d0afbfe16565efdf7b9fcfc69942fc1 (diff)
e1: Major update: use double-buffering for SSC rx/tx; USB receive works
Diffstat (limited to 'sam')
-rw-r--r--sam/applications/sam_e1/e1_ssc_tc.c139
-rw-r--r--sam/applications/sam_e1/e1_ssc_tc.h9
-rw-r--r--sam/applications/sam_e1/main.c123
3 files changed, 138 insertions, 133 deletions
diff --git a/sam/applications/sam_e1/e1_ssc_tc.c b/sam/applications/sam_e1/e1_ssc_tc.c
index 4b0370a2..9e6e8701 100644
--- a/sam/applications/sam_e1/e1_ssc_tc.c
+++ b/sam/applications/sam_e1/e1_ssc_tc.c
@@ -3,36 +3,13 @@
#include <string.h>
#include <asf.h>
#include "conf_board.h"
+#include "e1_ssc_tc.h"
-/* enable Transmit support */
-#define TX_ENABLE
-
-static int g_ssc_num_overruns;
-static Pdc* g_pdc;
-
-
-/* 1024 bytes covers 32 frames of 32bytes (256bits) each.
- * At frame rate of 8000 Hz, this means 1024 bytes represent 4ms */
-#define BUFFER_SIZE 1024
-
-static uint8_t g_pdc_ssc_buffer0[BUFFER_SIZE];
-static pdc_packet_t g_pdc_ssc_rx_packet0 = {
- .ul_addr = &g_pdc_ssc_buffer0,
- .ul_size = BUFFER_SIZE/4, /* 32bit transfers, so 4 bytes per transfer */
-};
-static uint8_t g_pdc_ssc_buffer1[BUFFER_SIZE];
-static pdc_packet_t g_pdc_ssc_rx_packet1 = {
- .ul_addr = &g_pdc_ssc_buffer1,
- .ul_size = BUFFER_SIZE/4, /* 32bit transfers, so 4 bytes per transfer */
-};
-
-static uint8_t g_pdc_ssc_buffer2[BUFFER_SIZE];
-static pdc_packet_t g_pdc_ssc_tx_packet = {
- .ul_addr = &g_pdc_ssc_buffer2,
- .ul_size = BUFFER_SIZE/4, /* 32bit transfers, so 4 bytes per transfer */
-};
-
+#include <osmocom/core/utils.h>
+/***********************************************************************
+ * Timer/Counter block for FRAME generation
+ ***********************************************************************/
/* We use one timer/counter block to generate an artificial frame signal from the
* received/recovered clock, which we then feed into the SSC for bit/octet-alignment */
@@ -41,7 +18,7 @@ static pdc_packet_t g_pdc_ssc_tx_packet = {
#define TC_ALIGN TC1 /* instance 1 */
#define TC_CHANNEL_ALIGN 1 /* TC1 on instance 1 */
-void e1_tc_align_init()
+void e1_tc_align_init(void)
{
printf("%s\n\r", __func__);
sysclk_enable_peripheral_clock(ID_TC_ALIGN);
@@ -70,27 +47,103 @@ void e1_tc_align_init()
tc_start(TC_ALIGN, TC_CHANNEL_ALIGN);
}
-uint32_t e1_tc_align_read()
+uint32_t e1_tc_align_read(void)
{
return tc_read_cv(TC_ALIGN, TC_CHANNEL_ALIGN);
}
+void e1_tc_align_set(uint8_t pos)
+{
+ tc_write_ra(TC_ALIGN, TC_CHANNEL_ALIGN, pos);
+ tc_write_rb(TC_ALIGN, TC_CHANNEL_ALIGN, (pos+16)%256);
+ tc_start(TC_ALIGN, TC_CHANNEL_ALIGN);
+}
+
+
+
+/***********************************************************************
+ * SSC code (using PDC)
+ ***********************************************************************/
+
+/* enable Transmit support */
+#define TX_ENABLE
+
+static int g_ssc_num_overruns;
+static Pdc* g_pdc;
+
+
+/* 1024 bytes covers 32 frames of 32bytes (256bits) each.
+ * At frame rate of 8000 Hz, this means 1024 bytes represent 4ms */
+#define BUFFER_SIZE 1024
+#define NUM_RX_BUF_SSC 2
+#define NUM_TX_BUF_SSC 2
+
+struct ssc_buffer {
+ uint8_t buffer[BUFFER_SIZE];
+ pdc_packet_t packet;
+};
+
+static int g_pdc_ssc_cur_rx_idx = 0;
+static struct ssc_buffer g_pdc_ssc_rx_buffer[NUM_RX_BUF_SSC];
+static int g_pdc_ssc_cur_tx_idx = 0;
+static struct ssc_buffer g_pdc_ssc_tx_buffer[NUM_TX_BUF_SSC];
+
+static void ssc_buffer_init(struct ssc_buffer *buf, unsigned int num)
+{
+ unsigned int i;
+ for (i = 0; i < num; i++) {
+ buf[i].packet.ul_addr = (uint32_t) &buf[i].buffer;
+ buf[i].packet.ul_size = sizeof(buf[i].buffer)/4;
+ }
+}
+
+static void usb_iso_in_cb(udd_ep_status_t status, iram_size_t nb_transfered, udd_ep_id_t ep)
+{
+ if (status != UDD_EP_TRANSFER_OK)
+ printf("U%d", status);
+}
+
/* Interrupt handler for SSC. Linker magic binds this function based on name (startup_sam4s.c) */
void SSC_Handler(void)
{
uint32_t status = ssc_get_status(SSC);
+ if (status & SSC_SR_ENDRX) {
+ struct ssc_buffer *sb_cur = &g_pdc_ssc_rx_buffer[g_pdc_ssc_cur_rx_idx];
+ int next_rx_idx = (g_pdc_ssc_cur_rx_idx + 1) % NUM_RX_BUF_SSC;
+ bool rc;
+ /* refill only the 'next' DMA buffer; PDC has copied previous next to current */
+ pdc_rx_init(g_pdc, NULL, &g_pdc_ssc_rx_buffer[next_rx_idx].packet);
+ //printf("E%d", g_pdc_ssc_cur_rx_idx);
+ /* FIXME: hand over to USB ISO IN */
+ rc = udi_vendor_iso_in_run(sb_cur->buffer, sizeof(sb_cur->buffer), usb_iso_in_cb);
+ if (rc == false) printf("x");
+ g_pdc_ssc_cur_rx_idx = next_rx_idx;
+ }
if (status & SSC_SR_RXBUFF) {
- //printf("R");
- pdc_rx_init(g_pdc, &g_pdc_ssc_rx_packet1, NULL); /* FIXME: swap buffers */
+ /* this means both current and next buffer have ended. Shouldn't happen,
+ * as due to double buffering we always refill the next buffer in ENDRX */
+ printf("RXBUFF!\r\n");
+ /* re-start from scratch */
+ g_pdc_ssc_cur_rx_idx = 0;
+ pdc_rx_init(g_pdc, &g_pdc_ssc_rx_buffer[0].packet, &g_pdc_ssc_rx_buffer[1].packet);
}
#ifdef TX_ENABLE
+ if (status & SSC_SR_ENDTX) {
+ int next_tx_idx = (g_pdc_ssc_cur_tx_idx + 1) % NUM_TX_BUF_SSC;
+ pdc_tx_init(g_pdc, NULL, &g_pdc_ssc_tx_buffer[next_tx_idx].packet);
+ //printf("e%d", g_pdc_ssc_cur_tx_idx);
+ g_pdc_ssc_cur_tx_idx = next_tx_idx;
+ }
if (status & SSC_SR_TXBUFE) {
- pdc_tx_init(g_pdc, &g_pdc_ssc_tx_packet, NULL);
+ printf("TXBUFE!\r\n");
+ g_pdc_ssc_cur_tx_idx = 0;
+ pdc_tx_init(g_pdc, &g_pdc_ssc_tx_buffer[0].packet, &g_pdc_ssc_tx_buffer[1].packet);
}
#endif
if (status & SSC_SR_OVRUN) {
g_ssc_num_overruns++;
+ printf("OVRUN!\r\n");
}
}
@@ -108,7 +161,7 @@ static void fill_tx_buf(uint8_t *buf, unsigned int size)
}
}
-void e1_init_gpio()
+void e1_init_gpio(void)
{
printf("%s\n\r", __func__);
@@ -136,11 +189,15 @@ void e1_init_gpio()
pio_configure_pin(PIO_PA13_IDX, PIO_PERIPH_A); /* LIU_MOSI */
}
-void e1_ssc_init()
+void e1_ssc_init(void)
{
g_pdc = ssc_get_pdc_base(SSC);
printf("%s\n\r", __func__);
- fill_tx_buf(g_pdc_ssc_buffer2, sizeof(g_pdc_ssc_buffer2));
+ ssc_buffer_init(g_pdc_ssc_rx_buffer, ARRAY_SIZE(g_pdc_ssc_rx_buffer));
+ ssc_buffer_init(g_pdc_ssc_tx_buffer, ARRAY_SIZE(g_pdc_ssc_tx_buffer));
+
+ for (int i = 0; i < ARRAY_SIZE(g_pdc_ssc_tx_buffer); i++)
+ fill_tx_buf(g_pdc_ssc_tx_buffer[i].buffer, sizeof(g_pdc_ssc_tx_buffer[i].buffer));
sysclk_enable_peripheral_clock(ID_SSC);
@@ -197,10 +254,10 @@ void e1_ssc_init()
#endif
/* set up Peripheral DMA controller */
- //pdc_rx_init(g_pdc, &g_pdc_ssc_rx_packet0, &g_pdc_ssc_rx_packet1);
- pdc_rx_init(g_pdc, &g_pdc_ssc_rx_packet0, NULL);
+ g_pdc_ssc_cur_rx_idx = 0;
+ pdc_rx_init(g_pdc, &g_pdc_ssc_rx_buffer[0].packet, &g_pdc_ssc_rx_buffer[1].packet);
#ifdef TX_ENABLE
- pdc_tx_init(g_pdc, &g_pdc_ssc_tx_packet, NULL);
+ pdc_tx_init(g_pdc, &g_pdc_ssc_tx_buffer[0].packet, &g_pdc_ssc_tx_buffer[1].packet);
#endif
pdc_enable_transfer(g_pdc, PERIPH_PTCR_RXTEN
#ifdef TX_ENABLE
@@ -216,9 +273,9 @@ void e1_ssc_init()
NVIC_EnableIRQ(SSC_IRQn);
/* enable SSC interrupts */
- ssc_enable_interrupt(SSC, SSC_IER_RXBUFF
+ ssc_enable_interrupt(SSC, SSC_IER_RXBUFF | SSC_IER_ENDRX | SSC_IER_OVRUN
#ifdef TX_ENABLE
- | SSC_IER_TXBUFE
+ | SSC_IER_TXBUFE | SSC_IER_ENDTX
#endif
);
diff --git a/sam/applications/sam_e1/e1_ssc_tc.h b/sam/applications/sam_e1/e1_ssc_tc.h
index ac573a7e..6052cd56 100644
--- a/sam/applications/sam_e1/e1_ssc_tc.h
+++ b/sam/applications/sam_e1/e1_ssc_tc.h
@@ -1,5 +1,8 @@
#pragma once
-void e1_init_gpio();
-void e1_tc_align_init();
-void e1_ssc_init();
+void e1_tc_align_init(void);
+uint32_t e1_tc_align_read(void);
+void e1_tc_align_set(uint8_t pos);
+
+void e1_init_gpio(void);
+void e1_ssc_init(void);
diff --git a/sam/applications/sam_e1/main.c b/sam/applications/sam_e1/main.c
index f6472360..b31409c2 100644
--- a/sam/applications/sam_e1/main.c
+++ b/sam/applications/sam_e1/main.c
@@ -1,95 +1,11 @@
-/**
- * \file
- *
- * \brief Low Power Application.
- *
- * Copyright (c) 2012-2016 Atmel Corporation. All rights reserved.
- *
- * \asf_license_start
- *
- * \page License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * 3. The name of Atmel may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * 4. This software may only be redistributed and used in connection with an
- * Atmel microcontroller product.
- *
- * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
- * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * \asf_license_stop
- *
- */
-
-/**
- * \mainpage Low Power Application
- *
- * \section Purpose
- *
- * This example shows all the different low power modes with several types
- * of wake-up sources. And the consumption of the core in different power
- * modes can be measured.
- *
- * \section Requirements
- *
- * This package can be used with SAM evaluation kits.
- *
- * \section Description
- *
- * The program will display a menu on console. It allows users to change the
- * configuration and enter into a different power mode, and then measure the
- * power consumption.
- *
- * For Eks, an amperemeter has to be plugged on the board instead of the
- * VDDx jumper.
- *
- * Note that for better consumption measurement:
- * - Run program out of flash without ICE connected.
- *
- * \section Usage
- *
- * -# Build the program and download it into the evaluation board.
- * -# On the computer, open and configure a terminal application
- * (e.g., HyperTerminal on Microsoft Windows) with these settings:
- * - 115200 bauds
- * - 8 bits of data
- * - No parity
- * - 1 stop bit
- * - No flow control
- * -# Start the application.
- */
-/*
- * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
- */
-
#include <asf.h>
#include "stdio_serial.h"
#include "conf_board.h"
#include "conf_clock.h"
#include "conf_uart_serial.h"
#include "conf_usb.h"
-#include "low_power_board.h"
#include "e1_ssc_tc.h"
+#include "low_power_board.h"
#include "idt82v2081_asf.h"
#include "microvty.h"
@@ -147,6 +63,8 @@
/** Current MCK in Hz */
uint32_t g_ul_current_mck;
+volatile uint32_t g_ul_ms_ticks;
+
/** Button pressed flag */
volatile uint32_t g_ul_button_pressed = 0;
@@ -404,6 +322,24 @@ DEFUN(vty_idt_write, idt_write_cmd, "idt-write", "Write to SPI register")
printf("IDT82 Register 0x%02lx: Written 0x%02lx\r\n", reg, val);
}
+DEFUN(vty_tca_write, tca_write_cmd, "tc-align-write", "Write to TC Align register")
+{
+ long val;
+
+ if (argc < 2) {
+ printf("You must specify the value\r\n");
+ return;
+ }
+ val = strtol(argv[1], NULL, 0);
+
+ if (val < 0 || val > 256) {
+ printf("Value out of range <0..255>\r\n");
+ return;
+ }
+
+ e1_tc_align_set(val);
+}
+
static void main_vbus_action(bool b_high)
{
@@ -413,6 +349,11 @@ static void main_vbus_action(bool b_high)
udc_detach();
}
+void SysTick_Handler(void)
+{
+ g_ul_ms_ticks++;
+}
+
/**
* \brief Low power application entry point.
*
@@ -424,6 +365,10 @@ int main(void)
sysclk_init();
g_ul_current_mck = sysclk_get_cpu_hz();
board_init();
+ SysTick_Config(sysclk_get_cpu_hz() / 1000);
+
+ udc_start();
+ udc_detach();
/* Initialize the console uart */
configure_console();
@@ -432,15 +377,15 @@ int main(void)
microvty_register(&idt_read_cmd);
microvty_register(&idt_write_cmd);
microvty_register(&tc_dump_cv_cmd);
-
- /* Output example information */
- puts(STRING_HEADER);
+ microvty_register(&tca_write_cmd);
/* Set default clock and re-configure UART */
set_default_working_clock();
reconfigure_console(g_ul_current_mck, CONF_UART_BAUDRATE);
- udc_start();
+ /* Output example information */
+ puts(STRING_HEADER);
+
if (!udc_include_vbus_monitoring())
main_vbus_action(true);