303 lines
6.8 KiB
C
303 lines
6.8 KiB
C
/*
|
|
* This file is part of the Black Magic Debug project.
|
|
*
|
|
* Copyright (C) 2018 Flirc Inc.
|
|
* Written by Jason Kotzin <jasonkotzin@gmail.com>
|
|
*
|
|
* This library is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "general.h"
|
|
#include "gdb_if.h"
|
|
#include "cdcacm.h"
|
|
#include "usbuart.h"
|
|
|
|
#include <libopencm3/sam/d/nvic.h>
|
|
#include <libopencm3/sam/d/port.h>
|
|
#include <libopencm3/sam/d/gclk.h>
|
|
#include <libopencm3/sam/d/pm.h>
|
|
#include <libopencm3/sam/d/uart.h>
|
|
#include <libopencm3/sam/d/adc.h>
|
|
|
|
#include <libopencm3/cm3/systick.h>
|
|
#include <libopencm3/cm3/scb.h>
|
|
|
|
static struct gclk_hw clock = {
|
|
.gclk0 = SRC_DFLL48M,
|
|
.gclk1 = SRC_OSC8M,
|
|
.gclk1_div = 30, /* divide clock for ADC */
|
|
.gclk2 = SRC_OSC8M,
|
|
.gclk2_div = 100, /* divide clock for TC */
|
|
.gclk3 = SRC_DFLL48M,
|
|
.gclk4 = SRC_DFLL48M,
|
|
.gclk5 = SRC_DFLL48M,
|
|
.gclk6 = SRC_DFLL48M,
|
|
.gclk7 = SRC_DFLL48M,
|
|
};
|
|
|
|
extern void trace_tick(void);
|
|
|
|
uint8_t running_status;
|
|
static volatile uint32_t time_ms;
|
|
|
|
uint8_t button_pressed;
|
|
//static volatile uint32_t button_counter;
|
|
|
|
void sys_tick_handler(void)
|
|
{
|
|
if(running_status)
|
|
gpio_toggle(LED_PORT, LED_IDLE_RUN);
|
|
|
|
time_ms += 10;
|
|
|
|
uart_pop();
|
|
}
|
|
|
|
uint32_t platform_time_ms(void)
|
|
{
|
|
return time_ms;
|
|
}
|
|
|
|
static void usb_setup(void)
|
|
{
|
|
/* Enable USB */
|
|
INSERTBF(PM_APBBMASK_USB, 1, PM->apbbmask);
|
|
|
|
/* enable clocking to usb */
|
|
set_periph_clk(GCLK0, GCLK_ID_USB);
|
|
periph_clk_en(GCLK_ID_USB, 1);
|
|
|
|
gpio_config_special(PORTA, GPIO24, SOC_GPIO_PERIPH_G);
|
|
gpio_config_special(PORTA, GPIO25, SOC_GPIO_PERIPH_G);
|
|
|
|
}
|
|
|
|
static uint32_t timing_init(void)
|
|
{
|
|
uint32_t cal = 0;
|
|
|
|
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
|
|
systick_set_reload(4800); /* Interrupt us at 10 Hz */
|
|
systick_interrupt_enable();
|
|
|
|
systick_counter_enable();
|
|
return cal;
|
|
}
|
|
|
|
static void adc_init(void)
|
|
{
|
|
gpio_config_special(ADC_PORT, ADC_POS_PIN, SOC_GPIO_PERIPH_B); /* +input */
|
|
gpio_config_special(ADC_PORT, ADC_REF_PIN, SOC_GPIO_PERIPH_B); /* reference */
|
|
|
|
set_periph_clk(GCLK1, GCLK_ID_ADC);
|
|
periph_clk_en(GCLK_ID_ADC, 1);
|
|
|
|
adc_enable(ADC_REFCTRL_VREFA,0,ADC_INPUTCTRL_GND,ADC_MUXPOS);
|
|
}
|
|
|
|
#define EIC 0x40001800
|
|
#define EIC_CONFIG1 0x4000181C
|
|
#define EIC_INTENSET 0x4000180C
|
|
|
|
#define TC3 0x42002C00
|
|
|
|
static void counter_init(void)
|
|
{
|
|
/* enable bus and clock */
|
|
INSERTBF(PM_APBCMASK_TC3, 1, PM->apbcmask);
|
|
|
|
set_periph_clk(GCLK2, GCLK_ID_TC3);
|
|
periph_clk_en(GCLK_ID_TC3, 1);
|
|
|
|
/* reset */
|
|
*((uint16_t*)TC3) = 1;
|
|
|
|
/* set CTRLA.MODE (default 16-bit) */
|
|
/* set CTRLA.WAVEGEN */
|
|
/* set CTRLA.PRESCALER and CTRLA.PRESYNC */
|
|
*((uint16_t*)TC3) = (7<<8); //| (1<<12);
|
|
|
|
/* set CC0 (approx. 5 seconds delay) */
|
|
*((uint16_t*)(0x42002C18)) = 1000;
|
|
|
|
/* enable MC0 interrupt */
|
|
*((uint8_t*)(0x42002C0D)) = (1<<4);
|
|
nvic_enable_irq(NVIC_TC3_IRQ);
|
|
|
|
/* set CTRLBSET.ONESHOT */
|
|
/* enable the TC */
|
|
}
|
|
|
|
static void button_init(void)
|
|
{
|
|
#if 1
|
|
gpio_config_special(BUTTON_PORT, BUTTON_PIN, SOC_GPIO_PERIPH_A);
|
|
|
|
INSERTBF(PM_APBAMASK_EIC, 1, PM->apbamask);
|
|
|
|
set_periph_clk(GCLK0, GCLK_ID_EIC);
|
|
periph_clk_en(GCLK_ID_EIC, 1);
|
|
|
|
/* configure r/f edge, enable filtering */
|
|
//EIC->evctrl = (1<<15);
|
|
*((uint32_t*)EIC_CONFIG1) = ((2+8)<<28);
|
|
|
|
/* enable the IEC */
|
|
*((uint8_t*)EIC) = (1<<1);
|
|
|
|
/* enable interrupts */
|
|
*((uint32_t*)EIC_INTENSET) = (1<<15);
|
|
nvic_enable_irq(NVIC_EIC_IRQ);
|
|
|
|
//button_counter = 0;
|
|
#else
|
|
gpio_config_input(BUTTON_PORT, BUTTON_PIN, 0);
|
|
#endif
|
|
}
|
|
|
|
void platform_init(void)
|
|
{
|
|
gclk_init(&clock);
|
|
|
|
usb_setup();
|
|
|
|
gpio_config_output(LED_PORT, LED_IDLE_RUN, 0);
|
|
gpio_config_output(TMS_PORT, TMS_PIN, 0);
|
|
gpio_config_output(TCK_PORT, TCK_PIN, 0);
|
|
gpio_config_output(TDI_PORT, TDI_PIN, 0);
|
|
|
|
gpio_config_output(TMS_PORT, TMS_DIR_PIN, 0);
|
|
|
|
/* enable both input and output with pullup disabled by default */
|
|
PORT_DIRSET(SWDIO_PORT) = SWDIO_PIN;
|
|
PORT_PINCFG(SWDIO_PORT, SWDIO_PIN_NUM) |= GPIO_PINCFG_INEN | GPIO_PINCFG_PULLEN;
|
|
gpio_clear(SWDIO_PORT, SWDIO_PIN);
|
|
|
|
/* configure swclk_pin as output */
|
|
gpio_config_output(SWCLK_PORT, SWCLK_PIN, 0);
|
|
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
|
|
|
gpio_config_input(TDO_PORT, TDO_PIN, 0);
|
|
gpio_config_output(SRST_PORT, SRST_PIN, GPIO_OUT_FLAG_DEFAULT_HIGH);
|
|
gpio_clear(SRST_PORT, SRST_PIN);
|
|
|
|
/* setup uart led, disable by default*/
|
|
gpio_config_output(LED_PORT_UART, LED_UART, 0);//GPIO_OUT_FLAG_DEFAULT_HIGH);
|
|
gpio_clear(LED_PORT_UART, LED_UART);
|
|
|
|
|
|
timing_init();
|
|
usbuart_init();
|
|
cdcacm_init();
|
|
adc_init();
|
|
counter_init();
|
|
button_init();
|
|
}
|
|
|
|
void platform_srst_set_val(bool assert)
|
|
{
|
|
volatile int i;
|
|
if (!assert) {
|
|
gpio_clear(SRST_PORT, SRST_PIN);
|
|
for(i = 0; i < 10000; i++) asm("nop");
|
|
} else {
|
|
gpio_set(SRST_PORT, SRST_PIN);
|
|
}
|
|
}
|
|
|
|
bool platform_srst_get_val(void)
|
|
{
|
|
return gpio_get(SRST_PORT, SRST_PIN) != 0;
|
|
}
|
|
|
|
void platform_delay(uint32_t ms)
|
|
{
|
|
platform_timeout timeout;
|
|
platform_timeout_set(&timeout, ms);
|
|
while (!platform_timeout_is_expired(&timeout));
|
|
}
|
|
|
|
const char *platform_target_voltage(void)
|
|
{
|
|
uint32_t voltage;
|
|
static char out[] = "0.0V";
|
|
|
|
adc_start();
|
|
|
|
while (!(1&(ADC->intflag)));
|
|
voltage = ((485*adc_result())>>12); /* 330 without divider, 485 with it */
|
|
|
|
out[0] = '0' + (char)(voltage/100);
|
|
out[2] = '0' + (char)((voltage/10) % 10);
|
|
|
|
return out;
|
|
}
|
|
|
|
char *serialno_read(char *s)
|
|
{
|
|
int i;
|
|
volatile uint32_t unique_id = *(volatile uint32_t *)0x0080A00C +
|
|
*(volatile uint32_t *)0x0080A040 +
|
|
*(volatile uint32_t *)0x0080A044 +
|
|
*(volatile uint32_t *)0x0080A048;
|
|
|
|
/* Fetch serial number from chip's unique ID */
|
|
for(i = 0; i < 8; i++) {
|
|
s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';
|
|
}
|
|
|
|
for(i = 0; i < 8; i++)
|
|
if(s[i] > '9')
|
|
s[i] += 'A' - '9' - 1;
|
|
s[8] = 0;
|
|
|
|
return s;
|
|
}
|
|
|
|
void platform_request_boot(void)
|
|
{
|
|
}
|
|
|
|
void eic_isr(void)
|
|
{
|
|
if (!button_pressed){
|
|
/* set to rising-edge detection */
|
|
*((uint32_t*)EIC_CONFIG1) = ((1+8)<<28);
|
|
|
|
/* enable counter */
|
|
*((uint16_t*)TC3) |= 2;
|
|
//*((uint8_t*)(0x42002C05)) = (1<<6);
|
|
|
|
button_pressed = 1;
|
|
} else {
|
|
/* set to falling-edge detection */
|
|
*((uint32_t*)EIC_CONFIG1) = ((2+8)<<28);
|
|
|
|
/* disable and reset counter */
|
|
*((uint16_t*)TC3) &= ~2;
|
|
*((uint16_t*)(0x42002C10)) = 0;
|
|
|
|
button_pressed = 0;
|
|
}
|
|
|
|
/* clear the interrupt */
|
|
*((uint32_t*)0x40001810) = (1<<15);
|
|
}
|
|
|
|
void tc3_isr(void)
|
|
{
|
|
if ((*((uint8_t*)(0x42002C0E)) & 16))
|
|
scb_reset_system();
|
|
}
|