Merge pull request #692 from miek/m0_sgpio
Use the M0 core to handle SGPIO samples
This commit is contained in:
@ -34,3 +34,6 @@ MEMORY
|
|||||||
}
|
}
|
||||||
|
|
||||||
usb_bulk_buffer = ORIGIN(ram_usb);
|
usb_bulk_buffer = ORIGIN(ram_usb);
|
||||||
|
usb_bulk_buffer_offset = ORIGIN(ram_shared);
|
||||||
|
usb_bulk_buffer_tx = ORIGIN(ram_shared)+4;
|
||||||
|
PROVIDE(__ram_m0_start__ = ORIGIN(ram_m0));
|
||||||
|
@ -26,8 +26,6 @@
|
|||||||
#include <libopencm3/lpc43xx/sgpio.h>
|
#include <libopencm3/lpc43xx/sgpio.h>
|
||||||
|
|
||||||
void baseband_streaming_enable(sgpio_config_t* const sgpio_config) {
|
void baseband_streaming_enable(sgpio_config_t* const sgpio_config) {
|
||||||
nvic_set_priority(NVIC_SGPIO_IRQ, 0);
|
|
||||||
nvic_enable_irq(NVIC_SGPIO_IRQ);
|
|
||||||
SGPIO_SET_EN_1 = (1 << SGPIO_SLICE_A);
|
SGPIO_SET_EN_1 = (1 << SGPIO_SLICE_A);
|
||||||
|
|
||||||
sgpio_cpld_stream_enable(sgpio_config);
|
sgpio_cpld_stream_enable(sgpio_config);
|
||||||
@ -35,6 +33,4 @@ void baseband_streaming_enable(sgpio_config_t* const sgpio_config) {
|
|||||||
|
|
||||||
void baseband_streaming_disable(sgpio_config_t* const sgpio_config) {
|
void baseband_streaming_disable(sgpio_config_t* const sgpio_config) {
|
||||||
sgpio_cpld_stream_disable(sgpio_config);
|
sgpio_cpld_stream_disable(sgpio_config);
|
||||||
|
|
||||||
nvic_disable_irq(NVIC_SGPIO_IRQ);
|
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,6 @@ set(SRC_M4
|
|||||||
hackrf_usb.c
|
hackrf_usb.c
|
||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/tuning.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/tuning.c"
|
||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/streaming.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/streaming.c"
|
||||||
sgpio_isr.c
|
|
||||||
usb_bulk_buffer.c
|
usb_bulk_buffer.c
|
||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/usb.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/usb.c"
|
||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/usb_request.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/usb_request.c"
|
||||||
@ -63,6 +62,8 @@ set(SRC_M4
|
|||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/operacake.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/operacake.c"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(SRC_M0 sgpio_m0.s)
|
||||||
|
|
||||||
if(BOARD STREQUAL "HACKRF_ONE")
|
if(BOARD STREQUAL "HACKRF_ONE")
|
||||||
SET(SRC_M4
|
SET(SRC_M4
|
||||||
${SRC_M4}
|
${SRC_M4}
|
||||||
|
@ -22,7 +22,9 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <libopencm3/lpc43xx/ipc.h>
|
||||||
#include <libopencm3/lpc43xx/m4/nvic.h>
|
#include <libopencm3/lpc43xx/m4/nvic.h>
|
||||||
|
#include <libopencm3/lpc43xx/rgu.h>
|
||||||
|
|
||||||
#include <streaming.h>
|
#include <streaming.h>
|
||||||
|
|
||||||
@ -50,6 +52,10 @@
|
|||||||
|
|
||||||
#include "hackrf-ui.h"
|
#include "hackrf-ui.h"
|
||||||
|
|
||||||
|
extern uint32_t __m0_start__;
|
||||||
|
extern uint32_t __m0_end__;
|
||||||
|
extern uint32_t __ram_m0_start__;
|
||||||
|
|
||||||
static usb_request_handler_fn vendor_request_handler[] = {
|
static usb_request_handler_fn vendor_request_handler[] = {
|
||||||
NULL,
|
NULL,
|
||||||
usb_vendor_request_set_transceiver_mode,
|
usb_vendor_request_set_transceiver_mode,
|
||||||
@ -176,6 +182,16 @@ static bool cpld_jtag_sram_load(jtag_t* const jtag) {
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void m0_rom_to_ram() {
|
||||||
|
uint32_t *dest = &__ram_m0_start__;
|
||||||
|
uint32_t *src = &__m0_start__;
|
||||||
|
while (src < &__m0_end__) {
|
||||||
|
*dest = *src;
|
||||||
|
dest++;
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
bool operacake_allow_gpio;
|
bool operacake_allow_gpio;
|
||||||
pin_setup();
|
pin_setup();
|
||||||
@ -188,6 +204,10 @@ int main(void) {
|
|||||||
#endif
|
#endif
|
||||||
cpu_clock_init();
|
cpu_clock_init();
|
||||||
|
|
||||||
|
/* Wake the M0 */
|
||||||
|
m0_rom_to_ram();
|
||||||
|
ipc_start_m0((uint32_t)&__ram_m0_start__);
|
||||||
|
|
||||||
if( !cpld_jtag_sram_load(&jtag_cpld) ) {
|
if( !cpld_jtag_sram_load(&jtag_cpld) ) {
|
||||||
halt_and_flash(6000000);
|
halt_and_flash(6000000);
|
||||||
}
|
}
|
||||||
@ -229,6 +249,7 @@ int main(void) {
|
|||||||
operacake_init(operacake_allow_gpio);
|
operacake_init(operacake_allow_gpio);
|
||||||
|
|
||||||
unsigned int phase = 0;
|
unsigned int phase = 0;
|
||||||
|
usb_bulk_buffer_offset = 0;
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
// Check whether we need to initiate a CPLD update
|
// Check whether we need to initiate a CPLD update
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Jared Boone
|
|
||||||
* Copyright 2013 Benjamin Vernoux
|
|
||||||
*
|
|
||||||
* This file is part of HackRF.
|
|
||||||
*
|
|
||||||
* 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, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This program 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 General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "sgpio_isr.h"
|
|
||||||
|
|
||||||
#include <libopencm3/lpc43xx/sgpio.h>
|
|
||||||
|
|
||||||
#include "usb_bulk_buffer.h"
|
|
||||||
|
|
||||||
void sgpio_isr_rx() {
|
|
||||||
SGPIO_CLR_STATUS_1 = (1 << SGPIO_SLICE_A);
|
|
||||||
|
|
||||||
uint32_t* const p = (uint32_t*)&usb_bulk_buffer[usb_bulk_buffer_offset];
|
|
||||||
__asm__(
|
|
||||||
"ldr r0, [%[SGPIO_REG_SS], #44]\n\t"
|
|
||||||
"str r0, [%[p], #0]\n\t"
|
|
||||||
"ldr r0, [%[SGPIO_REG_SS], #20]\n\t"
|
|
||||||
"str r0, [%[p], #4]\n\t"
|
|
||||||
"ldr r0, [%[SGPIO_REG_SS], #40]\n\t"
|
|
||||||
"str r0, [%[p], #8]\n\t"
|
|
||||||
"ldr r0, [%[SGPIO_REG_SS], #8]\n\t"
|
|
||||||
"str r0, [%[p], #12]\n\t"
|
|
||||||
"ldr r0, [%[SGPIO_REG_SS], #36]\n\t"
|
|
||||||
"str r0, [%[p], #16]\n\t"
|
|
||||||
"ldr r0, [%[SGPIO_REG_SS], #16]\n\t"
|
|
||||||
"str r0, [%[p], #20]\n\t"
|
|
||||||
"ldr r0, [%[SGPIO_REG_SS], #32]\n\t"
|
|
||||||
"str r0, [%[p], #24]\n\t"
|
|
||||||
"ldr r0, [%[SGPIO_REG_SS], #0]\n\t"
|
|
||||||
"str r0, [%[p], #28]\n\t"
|
|
||||||
:
|
|
||||||
: [SGPIO_REG_SS] "l" (SGPIO_PORT_BASE + 0x100),
|
|
||||||
[p] "l" (p)
|
|
||||||
: "r0"
|
|
||||||
);
|
|
||||||
usb_bulk_buffer_offset = (usb_bulk_buffer_offset + 32) & usb_bulk_buffer_mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sgpio_isr_tx() {
|
|
||||||
SGPIO_CLR_STATUS_1 = (1 << SGPIO_SLICE_A);
|
|
||||||
|
|
||||||
uint32_t* const p = (uint32_t*)&usb_bulk_buffer[usb_bulk_buffer_offset];
|
|
||||||
__asm__(
|
|
||||||
"ldr r0, [%[p], #0]\n\t"
|
|
||||||
"str r0, [%[SGPIO_REG_SS], #44]\n\t"
|
|
||||||
"ldr r0, [%[p], #4]\n\t"
|
|
||||||
"str r0, [%[SGPIO_REG_SS], #20]\n\t"
|
|
||||||
"ldr r0, [%[p], #8]\n\t"
|
|
||||||
"str r0, [%[SGPIO_REG_SS], #40]\n\t"
|
|
||||||
"ldr r0, [%[p], #12]\n\t"
|
|
||||||
"str r0, [%[SGPIO_REG_SS], #8]\n\t"
|
|
||||||
"ldr r0, [%[p], #16]\n\t"
|
|
||||||
"str r0, [%[SGPIO_REG_SS], #36]\n\t"
|
|
||||||
"ldr r0, [%[p], #20]\n\t"
|
|
||||||
"str r0, [%[SGPIO_REG_SS], #16]\n\t"
|
|
||||||
"ldr r0, [%[p], #24]\n\t"
|
|
||||||
"str r0, [%[SGPIO_REG_SS], #32]\n\t"
|
|
||||||
"ldr r0, [%[p], #28]\n\t"
|
|
||||||
"str r0, [%[SGPIO_REG_SS], #0]\n\t"
|
|
||||||
:
|
|
||||||
: [SGPIO_REG_SS] "l" (SGPIO_PORT_BASE + 0x100),
|
|
||||||
[p] "l" (p)
|
|
||||||
: "r0"
|
|
||||||
);
|
|
||||||
usb_bulk_buffer_offset = (usb_bulk_buffer_offset + 32) & usb_bulk_buffer_mask;
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Jared Boone
|
|
||||||
* Copyright 2013 Benjamin Vernoux
|
|
||||||
*
|
|
||||||
* This file is part of HackRF.
|
|
||||||
*
|
|
||||||
* 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, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This program 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 General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __SGPIO_ISR_H__
|
|
||||||
#define __SGPIO_ISR_H__
|
|
||||||
|
|
||||||
void sgpio_isr_rx();
|
|
||||||
void sgpio_isr_tx();
|
|
||||||
|
|
||||||
#endif/*__SGPIO_ISR_H__*/
|
|
108
firmware/hackrf_usb/sgpio_m0.s
Normal file
108
firmware/hackrf_usb/sgpio_m0.s
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of GreatFET
|
||||||
|
*
|
||||||
|
* Specialized SGPIO interrupt handler for Rhododendron.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// Constants that point to registers we'll need to modify in the SGPIO block.
|
||||||
|
.equ SGPIO_REGISTER_BLOCK_BASE, 0x40101000
|
||||||
|
.equ SGPIO_SHADOW_REGISTERS_BASE, 0x40101100
|
||||||
|
.equ SGPIO_EXCHANGE_INTERRUPT_CLEAR_REG, 0x40101F30
|
||||||
|
.equ SGPIO_EXCHANGE_INTERRUPT_STATUS_REG, 0x40101F2C
|
||||||
|
.equ SGPIO_GPIO_INPUT, 0x40101210
|
||||||
|
|
||||||
|
|
||||||
|
// Buffer that we're funneling data to/from.
|
||||||
|
.equ TARGET_DATA_BUFFER, 0x20008000
|
||||||
|
.equ TARGET_BUFFER_POSITION, 0x20007000
|
||||||
|
.equ TARGET_BUFFER_TX, 0x20007004
|
||||||
|
.equ TARGET_BUFFER_MASK, 0x7fff
|
||||||
|
|
||||||
|
.global main
|
||||||
|
.thumb_func
|
||||||
|
main:
|
||||||
|
|
||||||
|
// Spin until we're ready to handle an SGPIO packet:
|
||||||
|
// Grab the exchange interrupt staus...
|
||||||
|
ldr r0, =SGPIO_EXCHANGE_INTERRUPT_STATUS_REG
|
||||||
|
ldr r0, [r0]
|
||||||
|
|
||||||
|
// ... check to see if it has any interrupt bits set...
|
||||||
|
lsr r0, #1
|
||||||
|
|
||||||
|
// ... and if not, jump back to the beginning.
|
||||||
|
bcc main
|
||||||
|
|
||||||
|
// Clear the interrupt pending bits for the SGPIO slices we're working with.
|
||||||
|
ldr r0, =SGPIO_EXCHANGE_INTERRUPT_CLEAR_REG
|
||||||
|
ldr r1, =0xffff
|
||||||
|
str r1, [r0]
|
||||||
|
|
||||||
|
// Grab the base address of the SGPIO shadow registers...
|
||||||
|
ldr r7, =SGPIO_SHADOW_REGISTERS_BASE
|
||||||
|
|
||||||
|
// ... and grab the address of the buffer segment we want to write to / read from.
|
||||||
|
ldr r0, =TARGET_DATA_BUFFER // r0 = &buffer
|
||||||
|
ldr r3, =TARGET_BUFFER_POSITION // r3 = &position_in_buffer
|
||||||
|
ldr r2, [r3] // r2 = position_in_buffer
|
||||||
|
add r6, r0, r2 // r6 = buffer_target = &buffer + position_in_buffer
|
||||||
|
|
||||||
|
mov r8, r3 // Store &position_in_buffer.
|
||||||
|
|
||||||
|
// Our slice chain is set up as follows (ascending data age; arrows are reversed for flow):
|
||||||
|
// L -> F -> K -> C -> J -> E -> I -> A
|
||||||
|
// Which has equivalent shadow register offsets:
|
||||||
|
// 44 -> 20 -> 40 -> 8 -> 36 -> 16 -> 32 -> 0
|
||||||
|
|
||||||
|
// Load direction (TX or RX)
|
||||||
|
ldr r0, =TARGET_BUFFER_TX
|
||||||
|
ldr r0, [r0]
|
||||||
|
|
||||||
|
// TX?
|
||||||
|
lsr r0, #1
|
||||||
|
bcc direction_rx
|
||||||
|
|
||||||
|
direction_tx:
|
||||||
|
|
||||||
|
ldm r6!, {r0-r5}
|
||||||
|
str r0, [r7, #44]
|
||||||
|
str r1, [r7, #20]
|
||||||
|
str r2, [r7, #40]
|
||||||
|
str r3, [r7, #8 ]
|
||||||
|
str r4, [r7, #36]
|
||||||
|
str r5, [r7, #16]
|
||||||
|
|
||||||
|
ldm r6!, {r0-r1}
|
||||||
|
str r0, [r7, #32]
|
||||||
|
str r1, [r7, #0]
|
||||||
|
|
||||||
|
b done
|
||||||
|
|
||||||
|
direction_rx:
|
||||||
|
|
||||||
|
// 8 cycles
|
||||||
|
ldr r0, [r7, #44] // 2
|
||||||
|
ldr r1, [r7, #20] // 2
|
||||||
|
ldr r2, [r7, #40] // 2
|
||||||
|
ldr r3, [r7, #8 ] // 2
|
||||||
|
ldr r4, [r7, #36] // 2
|
||||||
|
ldr r5, [r7, #16] // 2
|
||||||
|
stm r6!, {r0-r5} // 7
|
||||||
|
|
||||||
|
// 6 cycles
|
||||||
|
ldr r0, [r7, #32] // 2
|
||||||
|
ldr r1, [r7, #0] // 2
|
||||||
|
stm r6!, {r0-r1}
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
// Finally, update the buffer location...
|
||||||
|
ldr r0, =TARGET_BUFFER_MASK
|
||||||
|
and r0, r6, r0 // r0 = (position_in_buffer + size_copied) % buffer_size
|
||||||
|
|
||||||
|
// ... restore &position_in_buffer, and store the new position there...
|
||||||
|
mov r1, r8
|
||||||
|
str r0, [r1] // position_in_buffer = (position_in_buffer + size_copied) % buffer_size
|
||||||
|
|
||||||
|
b main
|
@ -24,8 +24,7 @@
|
|||||||
|
|
||||||
#include "hackrf-ui.h"
|
#include "hackrf-ui.h"
|
||||||
#include <libopencm3/cm3/vector.h>
|
#include <libopencm3/cm3/vector.h>
|
||||||
#include <libopencm3/lpc43xx/m4/nvic.h>
|
#include "usb_bulk_buffer.h"
|
||||||
#include "sgpio_isr.h"
|
|
||||||
|
|
||||||
#include "usb_api_cpld.h" // Remove when CPLD update is handled elsewhere
|
#include "usb_api_cpld.h" // Remove when CPLD update is handled elsewhere
|
||||||
|
|
||||||
@ -257,18 +256,18 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) {
|
|||||||
led_on(LED2);
|
led_on(LED2);
|
||||||
usb_endpoint_init(&usb_endpoint_bulk_in);
|
usb_endpoint_init(&usb_endpoint_bulk_in);
|
||||||
rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_RX);
|
rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_RX);
|
||||||
vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_rx;
|
usb_bulk_buffer_tx = false;
|
||||||
} else if (_transceiver_mode == TRANSCEIVER_MODE_TX) {
|
} else if (_transceiver_mode == TRANSCEIVER_MODE_TX) {
|
||||||
led_off(LED2);
|
led_off(LED2);
|
||||||
led_on(LED3);
|
led_on(LED3);
|
||||||
usb_endpoint_init(&usb_endpoint_bulk_out);
|
usb_endpoint_init(&usb_endpoint_bulk_out);
|
||||||
rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_TX);
|
rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_TX);
|
||||||
vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_tx;
|
usb_bulk_buffer_tx = true;
|
||||||
} else {
|
} else {
|
||||||
led_off(LED2);
|
led_off(LED2);
|
||||||
led_off(LED3);
|
led_off(LED3);
|
||||||
rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_OFF);
|
rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_OFF);
|
||||||
vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_rx;
|
usb_bulk_buffer_tx = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,5 +22,4 @@
|
|||||||
|
|
||||||
#include "usb_bulk_buffer.h"
|
#include "usb_bulk_buffer.h"
|
||||||
|
|
||||||
const uint32_t usb_bulk_buffer_mask = 32768 - 1;
|
|
||||||
volatile uint32_t usb_bulk_buffer_offset = 0;
|
volatile uint32_t usb_bulk_buffer_offset = 0;
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#ifndef __USB_BULK_BUFFER_H__
|
#ifndef __USB_BULK_BUFFER_H__
|
||||||
#define __USB_BULK_BUFFER_H__
|
#define __USB_BULK_BUFFER_H__
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/* Address of usb_bulk_buffer is set in ldscripts. If you change the name of this
|
/* Address of usb_bulk_buffer is set in ldscripts. If you change the name of this
|
||||||
@ -31,8 +32,8 @@
|
|||||||
*/
|
*/
|
||||||
extern uint8_t usb_bulk_buffer[32768];
|
extern uint8_t usb_bulk_buffer[32768];
|
||||||
|
|
||||||
extern const uint32_t usb_bulk_buffer_mask;
|
|
||||||
|
|
||||||
extern volatile uint32_t usb_bulk_buffer_offset;
|
extern volatile uint32_t usb_bulk_buffer_offset;
|
||||||
|
|
||||||
|
extern bool usb_bulk_buffer_tx;
|
||||||
|
|
||||||
#endif/*__USB_BULK_BUFFER_H__*/
|
#endif/*__USB_BULK_BUFFER_H__*/
|
||||||
|
Reference in New Issue
Block a user