add PIO program for Sigma Delta 1-bit DAC

master
amedes 2021-12-19 11:54:12 +09:00
rodzic 0b9de7ccaf
commit ef4e067a1d
5 zmienionych plików z 152 dodań i 49 usunięć

Wyświetl plik

@ -22,6 +22,8 @@ add_executable(pico_tnc
kiss.c
)
pico_generate_pio_header(pico_tnc ${CMAKE_CURRENT_LIST_DIR}/pio_dac.pio)
target_include_directories(pico_tnc PRIVATE
include
)
@ -35,7 +37,7 @@ target_link_libraries(pico_tnc
hardware_pwm
hardware_uart
# For the dummy output:
#hardware_pio
hardware_pio
#pico_multicore
)

Wyświetl plik

@ -0,0 +1,40 @@
;
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
;
; SPDX-License-Identifier: BSD-3-Clause
;
.program pio_dac
; Repeatedly get one word of data from the TX FIFO, stalling when the FIFO is
; empty. Write the least significant bit to the OUT pin group.
.wrap_target
out pins, 1
.wrap
% c-sdk {
#include "hardware/clocks.h"
static inline void pio_dac_program_init(PIO pio, uint sm, uint offset, uint pin, float fs) {
pio_sm_config c = pio_dac_program_get_default_config(offset);
// Map the state machine's OUT pin group to one pin, namely the `pin`
// parameter to this function.
sm_config_set_out_shift(&c, true, true, 32);
sm_config_set_out_pins(&c, pin, 1);
sm_config_set_clkdiv(&c, (float)clock_get_hz(clk_sys) / fs);
// Set this pin's GPIO function (connect PIO to the pad)
pio_gpio_init(pio, pin);
// Set the pin direction to output at the PIO
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
// Load our configuration, and jump to the start of the program
pio_sm_init(pio, sm, offset, &c);
// Set the state machine running
pio_sm_set_enabled(pio, sm, true);
}
%}

Wyświetl plik

@ -1,29 +1,8 @@
/*
Copyright (c) 2021, JN1DFF
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* 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.
* Neither the name of the <organization> nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> 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.
*/
/**
* Copyright (c) 2021 JN1DFF
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* send.c - send packet
@ -37,15 +16,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "hardware/pwm.h"
#include "hardware/irq.h"
#include "hardware/sync.h"
#include "hardware/pio.h"
#include "hardware/structs/uart.h"
#include "pico/util/queue.h"
#include "pio_dac.pio.h"
#include "tnc.h"
#include "send.h"
#include "ax25.h"
//#include "wave_table.h"
#include "wave_table_132mhz.h"
#include "wave_table.h"
static const int pwm_pins[] = {
10, // port 0
@ -75,31 +57,30 @@ static void __isr dma_handler(void)
for (int i = 0; i < PORT_N; i++) {
tnc_t *tp = &tnc[i];
if (int_status & tp->data_chan_mask) {
if (int_status & tp->data_chan_mask) {
// generate modem signal
uint32_t *addr;
if (queue_try_remove(&tp->dac_queue, &addr)) {
// generate modem signal
uint32_t *addr;
if (queue_try_remove(&tp->dac_queue, &addr)) {
dma_channel_set_read_addr(tp->ctrl_chan, addr, true);
dma_channel_set_read_addr(tp->ctrl_chan, addr, true);
#if 0
printf("dma_hander: block = %p\n", &block[0]);
for (int i = 0; i < CONTROL_N + 1; i++) {
printf("block[%d] = %p\n", i, block[i]);
}
#endif
} else {
gpio_put(tp->ptt_pin, 0); // PTT off
pwm_set_chan_level(tp->pwm_slice, PWM_CHAN_A, 0); // set pwm level 0
tp->busy = false;
//printf("(%u) dma_handler: queue is empty, port = %d, data_chan = %d, ints = %08x\n", tnc_time(), tp->port, tp->data_chan, int_status);
} else {
gpio_put(tp->ptt_pin, 0); // PTT off
//pwm_set_chan_level(tp->pwm_slice, PWM_CHAN_A, 0); // set pwm level 0
tp->busy = false;
//printf("(%u) dma_handler: queue is empty, port = %d, data_chan = %d, ints = %08x\n", tnc_time(), tp->port, tp->data_chan, int_status);
}
//dma_hw->ints0 = tp->data_chan_mask;
}
//dma_hw->ints0 = tp->data_chan_mask;
}
} // for
dma_hw->ints0 = int_status;
}
static void send_start(tnc_t *tp)
@ -108,7 +89,7 @@ static void send_start(tnc_t *tp)
gpio_put(tp->ptt_pin, 1); // PTT on
tp->busy = true;
//printf("restart dma, ctrl = %08x, port = %d\n", dma_hw->ch[tp->data_chan].ctrl_trig, tp->port);
dma_channel_set_read_addr(tp->data_chan, NULL, true);
dma_channel_set_read_addr(tp->data_chan, NULL, true); // trigger NULL interrupt
}
}
@ -193,7 +174,7 @@ int send_byte(tnc_t *tp, uint8_t data, bool bit_stuff)
tp->dma_blocks[tp->next][idx] = NULL;
// send fsk data to dac queue
uint16_t const **block = &tp->dma_blocks[tp->next][0];
uint32_t const **block = &tp->dma_blocks[tp->next][0];
if (queue_try_add(&tp->dac_queue, &block)) {
#if 0
if (!tp->busy) {
@ -223,7 +204,12 @@ int send_byte(tnc_t *tp, uint8_t data, bool bit_stuff)
void send_init(void)
{
// set system clock, PWM uses system clock
set_sys_clock_khz(SYS_CLK_KHZ, true);
//set_sys_clock_khz(SYS_CLK_KHZ, true);
// pio_dac initialize
PIO pio = pio0;
// load pio_dac program
uint offset = pio_add_program(pio, &pio_dac_program);
// initialize tnc[]
for (int i = 0; i < PORT_N; i++) {
@ -241,6 +227,7 @@ void send_init(void)
gpio_set_dir(tp->ptt_pin, true); // output
gpio_put(tp->ptt_pin, 0);
#if 0
// PWM pins
tp->pwm_pin = pwm_pins[i];
// PWM configuration
@ -253,6 +240,12 @@ void send_init(void)
pwm_config_set_clkdiv_int(&pc, 1); // 1.0
pwm_config_set_wrap(&pc, PWM_CYCLE - 1);
pwm_init(tp->pwm_slice, &pc, true); // start PWM
#endif
// PIO
// find free state machine
uint sm = pio_claim_unused_sm(pio, true);
pio_dac_program_init(pio, sm, offset, pwm_pins[i], PIO_DAC_FS);
// DMA
tp->ctrl_chan = dma_claim_unused_channel(true);
@ -278,8 +271,8 @@ void send_init(void)
// DMA data channel
dc = dma_channel_get_default_config(tp->data_chan);
channel_config_set_transfer_data_size(&dc, DMA_SIZE_16); // PWM level is 16 bits
channel_config_set_dreq(&dc, DREQ_PWM_WRAP0 + tp->pwm_slice);
channel_config_set_transfer_data_size(&dc, DMA_SIZE_32); // pio_dac data size, 32bit
channel_config_set_dreq(&dc, pio_get_dreq(pio, sm, true)); // pio sm, TX
channel_config_set_chain_to(&dc, tp->ctrl_chan);
channel_config_set_irq_quiet(&dc, true);
// set high priority bit
@ -288,7 +281,7 @@ void send_init(void)
dma_channel_configure(
tp->data_chan,
&dc,
&pwm_hw->slice[tp->pwm_slice].cc,
&pio0_hw->txf[sm], // The initial write address
NULL, // Initial read address and transfer count are unimportant;
BIT_CYCLE, // audio data of 1/1200 s
false // Don't start yet.

Wyświetl plik

@ -33,7 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//#include "cmd.h"
// number of ports
#define PORT_N 1 // number of ports, 1..3
#define PORT_N 3 // number of ports, 1..3
#define BAUD_RATE 1200
#define SAMPLING_N 11
@ -163,7 +163,7 @@ typedef struct TNC {
int cnt_one;
// wave buffer for DMA
uint16_t const *dma_blocks[DAC_BLOCK_LEN][CONTROL_N + 1];
uint32_t const *dma_blocks[DAC_BLOCK_LEN][CONTROL_N + 1];
// send data queue
queue_t send_queue;

Wyświetl plik

@ -0,0 +1,68 @@
/**
* Copyright (c) 2021 JN1DFF
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
sine wave table for Bell202 AFSK signal
*/
#if 0
#define SYS_CLK_KHZ 132000
#define BIT_CYCLE 440
#define MARK_CYCLE 440
#define SPACE_CYCLE 240
#define MARK_TAB_LEN 807
#define SPACE_TAB_LEN 640
#define PWM_CYCLE 250
#endif
#define BAUD 1200 // bit rate
#define BIT_CYCLE 66 // DMA data words in 1/1200s
#define MARK_TAB_LEN 121 // 66 * 5/6 + 66
#define SPACE_TAB_LEN 96 // 36 * 5/6 + 66
#define PHASE_CYCLE 6
#define PIO_DAC_FS (BIT_CYCLE * BAUD * 32)
/* sine table for delta sigma modulation, 1200Hz */
static const uint32_t mark_tab[MARK_TAB_LEN] = {
0x20000200, 0x00010000, 0x00040004, 0x10008002, 0x40080100, 0x04020100, 0x02040404, 0x82082081,
0x84210420, 0x84442210, 0x44888888, 0x24491224, 0x4a492489, 0x94949492, 0x54a54a52, 0xaa9552a9,
0xaaaaaaaa, 0xaad55aaa, 0xb5ad6ad5, 0xd6dadad6, 0xb6db6db6, 0xeddb76dd, 0x7777776e, 0x7bddeef7,
0xbef7bdf7, 0xdfbefbef, 0xfbfbf7ef, 0xdfeff7fb, 0xbffbff7f, 0xfefffbff, 0xffbfffbf, 0xfdffff7f,
0xffffdfff, 0xffeffffe, 0xfbfffeff, 0xf7fff7ff, 0xff7ffdff, 0xfdffbff7, 0xbfbfdff7, 0xdfbfbfbf,
0xdf7efbef, 0xdef7defb, 0xddeef7bb, 0xeddddddd, 0x6edbb76e, 0xdb6db6db, 0xb6b6b6b6, 0x56ad6ad6,
0xaab556ab, 0xaa5556aa, 0xaa554aaa, 0x94a52a54, 0x92525252, 0x12492494, 0x48912249, 0x22222224,
0x10884422, 0x08210842, 0x02081042, 0x40404081, 0x01008040, 0x00801004, 0x40010008, 0x20002000,
0x00008000, 0x00400004, 0x20000200, 0x00010000, 0x00040004, 0x10008002, 0x40080100, 0x04020100,
0x02040404, 0x82082081, 0x84210420, 0x84442210, 0x44888888, 0x24491224, 0x4a492489, 0x94949492,
0x54a54a52, 0xaa9552a9, 0xaaaaaaaa, 0xaad55aaa, 0xb5ad6ad5, 0xd6dadad6, 0xb6db6db6, 0xeddb76dd,
0x7777776e, 0x7bddeef7, 0xbef7bdf7, 0xdfbefbef, 0xfbfbf7ef, 0xdfeff7fb, 0xbffbff7f, 0xfefffbff,
0xffbfffbf, 0xfdffff7f, 0xffffdfff, 0xffeffffe, 0xfbfffeff, 0xf7fff7ff, 0xff7ffdff, 0xfdffbff7,
0xbfbfdff7, 0xdfbfbfbf, 0xdf7efbef, 0xdef7defb, 0xddeef7bb, 0xeddddddd, 0x6edbb76e, 0xdb6db6db,
0xb6b6b6b6, 0x56ad6ad6, 0xaab556ab, 0xaa5556aa, 0xaa554aaa, 0x94a52a54, 0x92525252, 0x12492494,
0x48912249,
};
/* sine table for delta sigma modulation, 2200Hz */
static const uint32_t space_tab[SPACE_TAB_LEN] = {
0x10000200, 0x10002000, 0x20100200, 0x20404040, 0x44108208, 0x11111108, 0x24924489, 0xa9494949,
0x5552aa54, 0x55aad555, 0x6dadad6b, 0xb76dbb6d, 0x77bbbbbb, 0xfbefbdef, 0xbfdfbf7e, 0xbffbff7f,
0xf7fff7ff, 0xffffdfff, 0xffeffffe, 0xffbfffbf, 0xfdff7ff7, 0xfbf7f7fb, 0xef7bef7e, 0xbbbbbbbd,
0x6db76ddb, 0xad6b5b6b, 0x5556aad5, 0x54aa5555, 0x24a4a52a, 0x12449249, 0x21110911, 0x10420842,
0x02020408, 0x00801004, 0x00040008, 0x00400008, 0x10000200, 0x10002000, 0x20100200, 0x20404040,
0x44108208, 0x11111108, 0x24924489, 0xa9494949, 0x5552aa54, 0x55aad555, 0x6dadad6b, 0xb76dbb6d,
0x77bbbbbb, 0xfbefbdef, 0xbfdfbf7e, 0xbffbff7f, 0xf7fff7ff, 0xffffdfff, 0xffeffffe, 0xffbfffbf,
0xfdff7ff7, 0xfbf7f7fb, 0xef7bef7e, 0xbbbbbbbd, 0x6db76ddb, 0xad6b5b6b, 0x5556aad5, 0x54aa5555,
0x24a4a52a, 0x12449249, 0x21110911, 0x10420842, 0x02020408, 0x00801004, 0x00040008, 0x00400008,
0x10000200, 0x10002000, 0x20100200, 0x20404040, 0x44108208, 0x11111108, 0x24924489, 0xa9494949,
0x5552aa54, 0x55aad555, 0x6dadad6b, 0xb76dbb6d, 0x77bbbbbb, 0xfbefbdef, 0xbfdfbf7e, 0xbffbff7f,
0xf7fff7ff, 0xffffdfff, 0xffeffffe, 0xffbfffbf, 0xfdff7ff7, 0xfbf7f7fb, 0xef7bef7e, 0xbbbbbbbd,
};
/* sine table for different phase */
static const uint32_t *phase_tab[2][PHASE_CYCLE] = {
{ &space_tab[0], &space_tab[6], &space_tab[12], &space_tab[18], &space_tab[24], &space_tab[30], },
{ &mark_tab[0], &mark_tab[11], &mark_tab[22], &mark_tab[33], &mark_tab[44], &mark_tab[55], },
};