Skip to content

Commit

Permalink
optimize transfer over SPI during TX
Browse files Browse the repository at this point in the history
+ Transfer packet size in the same SPI transaction as the main body
+ Explicitly set FIFO_EMPTY interrupt and remove "append register" that creates 2 SPI transactions.
+ fix memory leak on linux
+ add transmit_fsk_raspberrypi example
  • Loading branch information
dernasherbrezon committed Jul 26, 2024
1 parent eaa7313 commit aea483f
Show file tree
Hide file tree
Showing 6 changed files with 435 additions and 168 deletions.
292 changes: 146 additions & 146 deletions examples/receive_fsk_raspberrypi/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,173 +42,173 @@
} while (0)

void rx_callback(sx127x *device, uint8_t *data, uint16_t data_length) {
uint8_t payload[2047];
const char SYMBOLS[] = "0123456789ABCDEF";
for (size_t i = 0; i < data_length; i++) {
uint8_t cur = data[i];
payload[2 * i] = SYMBOLS[cur >> 4];
payload[2 * i + 1] = SYMBOLS[cur & 0x0F];
}
payload[data_length * 2] = '\0';

int32_t frequency_error;
LINUX_NO_CODE_ERROR_CHECK(sx127x_rx_get_frequency_error(device, &frequency_error));
int16_t rssi;
int code = sx127x_rx_get_packet_rssi(device, &rssi);
if (code == SX127X_ERR_NOT_FOUND) {
fprintf(stdout, "received: %d %s freq_error: %" PRId32, data_length, payload, frequency_error);
} else {
fprintf(stdout, "received: %d %s rssi: %d freq_error: %" PRId32, data_length, payload, rssi, frequency_error);
}
uint8_t payload[2047];
const char SYMBOLS[] = "0123456789ABCDEF";
for (size_t i = 0; i < data_length; i++) {
uint8_t cur = data[i];
payload[2 * i] = SYMBOLS[cur >> 4];
payload[2 * i + 1] = SYMBOLS[cur & 0x0F];
}
payload[data_length * 2] = '\0';

int32_t frequency_error;
LINUX_NO_CODE_ERROR_CHECK(sx127x_rx_get_frequency_error(device, &frequency_error));
int16_t rssi;
int code = sx127x_rx_get_packet_rssi(device, &rssi);
if (code == SX127X_ERR_NOT_FOUND) {
fprintf(stdout, "received: %d %s freq_error: %" PRId32, data_length, payload, frequency_error);
} else {
fprintf(stdout, "received: %d %s rssi: %d freq_error: %" PRId32, data_length, payload, rssi, frequency_error);
}
}

int msleep(long msec) {
struct timespec ts;
int res;
struct timespec ts;
int res;

if (msec < 0) {
errno = EINVAL;
return EXIT_FAILURE;
}
if (msec < 0) {
errno = EINVAL;
return EXIT_FAILURE;
}

ts.tv_sec = msec / 1000;
ts.tv_nsec = (msec % 1000) * 1000000;
ts.tv_sec = msec / 1000;
ts.tv_nsec = (msec % 1000) * 1000000;

do {
res = nanosleep(&ts, &ts);
} while (res && errno == EINTR);
do {
res = nanosleep(&ts, &ts);
} while (res && errno == EINTR);

return res;
return res;
}

int gpio_write_value(int fd, int value) {
struct gpiohandle_data data;
data.values[0] = value;
int code = ioctl(fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
if (code < 0) {
perror("unable to write value");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
struct gpiohandle_data data;
data.values[0] = value;
int code = ioctl(fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
if (code < 0) {
perror("unable to write value");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

int reset_sx127x() {
int fd = open(GPIO_DEVICE, O_RDONLY);
if (fd < 0) {
perror("unable to open device");
return EXIT_FAILURE;
}
struct gpiohandle_request rq;
rq.lineoffsets[0] = GPIO_RESET_PIN;
rq.lines = 1;
rq.flags = GPIOHANDLE_REQUEST_OUTPUT;
strcpy(rq.consumer_label, "sx127x_reset");
int code = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &rq);
if (code < 0) {
perror("unable to reset chip");
return EXIT_FAILURE;
}
close(fd);

LINUX_ERROR_CHECK(gpio_write_value(rq.fd, 1));
LINUX_ERROR_CHECK(gpio_write_value(rq.fd, 0));
msleep(5);
LINUX_ERROR_CHECK(gpio_write_value(rq.fd, 1));
msleep(5);
close(rq.fd);
return EXIT_SUCCESS;
int fd = open(GPIO_DEVICE, O_RDONLY);
if (fd < 0) {
perror("unable to open device");
return EXIT_FAILURE;
}
struct gpiohandle_request rq;
rq.lineoffsets[0] = GPIO_RESET_PIN;
rq.lines = 1;
rq.flags = GPIOHANDLE_REQUEST_OUTPUT;
strcpy(rq.consumer_label, "sx127x_reset");
int code = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &rq);
if (code < 0) {
perror("unable to reset chip");
return EXIT_FAILURE;
}
close(fd);

LINUX_ERROR_CHECK(gpio_write_value(rq.fd, 1));
LINUX_ERROR_CHECK(gpio_write_value(rq.fd, 0));
msleep(5);
LINUX_ERROR_CHECK(gpio_write_value(rq.fd, 1));
msleep(5);
close(rq.fd);
return EXIT_SUCCESS;
}

int setup_and_wait_for_interrupt(sx127x *device) {
int fd = open(GPIO_DEVICE, O_RDONLY);
if (fd < 0) {
perror("unable to open device");
return EXIT_FAILURE;
}
uint8_t gpios[] = {GPIO_DIO0_PIN, GPIO_DIO1_PIN, GPIO_DIO2_PIN, GPIO_DIO3_PIN, GPIO_DIO4_PIN};
int gpios_length = sizeof(gpios);
struct pollfd pfd[5];
for (int i = 0; i < gpios_length; i++) {
struct gpioevent_request rq;
rq.lineoffset = gpios[i];
rq.eventflags = GPIOEVENT_EVENT_RISING_EDGE;
char label[] = "sx127x_fsk";
memcpy(rq.consumer_label, label, sizeof(label));
rq.handleflags = GPIOHANDLE_REQUEST_INPUT;

int code = ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &rq);
if (code < 0) {
perror("unable to setup gpio interrupt");
return EXIT_FAILURE;
}

pfd[i].fd = rq.fd;
pfd[i].events = POLLIN;
int fd = open(GPIO_DEVICE, O_RDONLY);
if (fd < 0) {
perror("unable to open device");
return EXIT_FAILURE;
}
uint8_t gpios[] = {GPIO_DIO0_PIN, GPIO_DIO1_PIN, GPIO_DIO2_PIN, GPIO_DIO3_PIN, GPIO_DIO4_PIN};
int gpios_length = sizeof(gpios);
struct pollfd pfd[5];
for (int i = 0; i < gpios_length; i++) {
struct gpioevent_request rq;
rq.lineoffset = gpios[i];
rq.eventflags = GPIOEVENT_EVENT_RISING_EDGE;
char label[] = "sx127x_fsk";
memcpy(rq.consumer_label, label, sizeof(label));
rq.handleflags = GPIOHANDLE_REQUEST_INPUT;

int code = ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &rq);
if (code < 0) {
perror("unable to setup gpio interrupt");
return EXIT_FAILURE;
}
close(fd);
fprintf(stdout, "waiting for packets...\n");
char buffer[32] = {0};
while (1) {
int code = poll(pfd, gpios_length, GPIO_POLL_TIMEOUT);
if (code < 0) {
perror("unable to receive gpio interrupt");
break;
}
for (int i = 0; i < gpios_length; i++) {
if (pfd[i].revents & POLLIN) {
// discard data
read(pfd[i].fd, buffer, 32);
}
}
sx127x_handle_interrupt(device);

pfd[i].fd = rq.fd;
pfd[i].events = POLLIN;
}
close(fd);
fprintf(stdout, "waiting for packets...\n");
char buffer[32] = {0};
while (1) {
int code = poll(pfd, gpios_length, GPIO_POLL_TIMEOUT);
if (code < 0) {
perror("unable to receive gpio interrupt");
break;
}
for (int i = 0; i < gpios_length; i++) {
close(pfd[i].fd);
if (pfd[i].revents & POLLIN) {
// discard data
read(pfd[i].fd, buffer, 32);
}
}
return EXIT_SUCCESS;
sx127x_handle_interrupt(device);
}
for (int i = 0; i < gpios_length; i++) {
close(pfd[i].fd);
}
return EXIT_SUCCESS;
}

int main() {
LINUX_ERROR_CHECK(reset_sx127x());

int spi_device_fd = open(SPI_DEVICE, O_RDWR);
if (spi_device_fd < 0) {
perror("unable to open device");
return EXIT_FAILURE;
}
int mode = SPI_MODE_0; // CPOL=0, CPHA=0
LINUX_ERROR_CHECK(ioctl(spi_device_fd, SPI_IOC_WR_MODE, &mode));
int bits_per_word = 0; // means 8 bits
LINUX_ERROR_CHECK(ioctl(spi_device_fd, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word));
int lsb_setting = 0; // MSB
LINUX_ERROR_CHECK(ioctl(spi_device_fd, SPI_IOC_WR_LSB_FIRST, &lsb_setting));
int max_speed = 4000000;
LINUX_ERROR_CHECK(ioctl(spi_device_fd, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed));

sx127x *device = NULL;
LINUX_ERROR_CHECK(sx127x_create(&spi_device_fd, &device));
LINUX_ERROR_CHECK(sx127x_set_opmod(SX127x_MODE_SLEEP, SX127x_MODULATION_FSK, device));
LINUX_ERROR_CHECK(sx127x_set_frequency(437200000, device));
LINUX_ERROR_CHECK(sx127x_set_opmod(SX127x_MODE_STANDBY, SX127x_MODULATION_FSK, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_set_bitrate(4800.0, device));
LINUX_ERROR_CHECK(sx127x_fsk_set_fdev(5000.0, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_rx_set_afc_auto(true, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_rx_set_afc_bandwidth(20000.0, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_rx_set_bandwidth(5000.0, device));
uint8_t syncWord[] = {0x12, 0xAD};
LINUX_ERROR_CHECK(sx127x_fsk_ook_set_syncword(syncWord, 2, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_set_address_filtering(SX127X_FILTER_NONE, 0, 0, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_set_packet_encoding(SX127X_NRZ, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_set_packet_format(SX127X_VARIABLE, 255, device));
LINUX_ERROR_CHECK(sx127x_fsk_set_data_shaping(SX127X_BT_0_5, SX127X_PA_RAMP_10, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_set_crc(SX127X_CRC_CCITT, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_rx_set_trigger(SX127X_RX_TRIGGER_RSSI_PREAMBLE, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_rx_set_rssi_config(SX127X_8, 0, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_rx_set_preamble_detector(true, 2, 0x0A, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_rx_calibrate(device));

sx127x_rx_set_callback(rx_callback, device);
LINUX_ERROR_CHECK(sx127x_set_opmod(SX127x_MODE_RX_CONT, SX127x_MODULATION_FSK, device));

return setup_and_wait_for_interrupt(device);
LINUX_ERROR_CHECK(reset_sx127x());

int spi_device_fd = open(SPI_DEVICE, O_RDWR);
if (spi_device_fd < 0) {
perror("unable to open device");
return EXIT_FAILURE;
}
int mode = SPI_MODE_0; // CPOL=0, CPHA=0
LINUX_ERROR_CHECK(ioctl(spi_device_fd, SPI_IOC_WR_MODE, &mode));
int bits_per_word = 0; // means 8 bits
LINUX_ERROR_CHECK(ioctl(spi_device_fd, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word));
int lsb_setting = 0; // MSB
LINUX_ERROR_CHECK(ioctl(spi_device_fd, SPI_IOC_WR_LSB_FIRST, &lsb_setting));
int max_speed = 4000000;
LINUX_ERROR_CHECK(ioctl(spi_device_fd, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed));

sx127x *device = NULL;
LINUX_ERROR_CHECK(sx127x_create(&spi_device_fd, &device));
LINUX_ERROR_CHECK(sx127x_set_opmod(SX127x_MODE_SLEEP, SX127x_MODULATION_FSK, device));
LINUX_ERROR_CHECK(sx127x_set_frequency(437200000, device));
LINUX_ERROR_CHECK(sx127x_set_opmod(SX127x_MODE_STANDBY, SX127x_MODULATION_FSK, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_set_bitrate(4800.0, device));
LINUX_ERROR_CHECK(sx127x_fsk_set_fdev(5000.0, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_rx_set_afc_auto(true, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_rx_set_afc_bandwidth(20000.0, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_rx_set_bandwidth(5000.0, device));
uint8_t syncWord[] = {0x12, 0xAD};
LINUX_ERROR_CHECK(sx127x_fsk_ook_set_syncword(syncWord, 2, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_set_address_filtering(SX127X_FILTER_NONE, 0, 0, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_set_packet_encoding(SX127X_NRZ, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_set_packet_format(SX127X_VARIABLE, 255, device));
LINUX_ERROR_CHECK(sx127x_fsk_set_data_shaping(SX127X_BT_0_5, SX127X_PA_RAMP_10, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_set_crc(SX127X_CRC_CCITT, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_rx_set_trigger(SX127X_RX_TRIGGER_RSSI_PREAMBLE, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_rx_set_rssi_config(SX127X_8, 0, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_rx_set_preamble_detector(true, 2, 0x0A, device));
LINUX_ERROR_CHECK(sx127x_fsk_ook_rx_calibrate(device));

sx127x_rx_set_callback(rx_callback, device);
LINUX_ERROR_CHECK(sx127x_set_opmod(SX127x_MODE_RX_CONT, SX127x_MODULATION_FSK, device));

return setup_and_wait_for_interrupt(device);
}
9 changes: 9 additions & 0 deletions examples/transmit_fsk_raspberrypi/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.5)
project(transmit_fsk_raspberrypi C)

set(CMAKE_C_STANDARD 99)

add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../ ${CMAKE_CURRENT_BINARY_DIR}/sx127x)

add_executable(transmit_fsk_raspberrypi main.c)
target_link_libraries(transmit_fsk_raspberrypi sx127x)
Loading

0 comments on commit aea483f

Please sign in to comment.