diff --git a/README.md b/README.md index b84e35b13a6cfe51a853562a0dad172d802448df..058f9a543a8b73042ee3fc8e8596d11f147ff011 100644 --- a/README.md +++ b/README.md @@ -55,14 +55,15 @@ You can use the pre-compiled minichlink or go to minichlink dir and `make` it. ``` cd examples/blink -make flash +make ``` -Just use `make` if you want to compile but not flash. +In Linux this will "just work"(TM) using `minichlink`. +In Windows, if you want to use minichlink, you will need to use Zadig to install WinUSB to the WCH-Link interface 0. +The generated .hex file is compatible with the official WCH flash tool. -In Linux this will "just work"(TM) using `minichlink`. -In Windows, if you want to use minichlink, you will need to use Zadig to install WinUSB to the WCH-Link interface 0. -The generated .hex file is compatible with the official WCH flash tool. +text = code, data = constants and initialization values, bss = uninitialized values. +dec is the sum of the 3 and reflects the number of bytes in flash that will get taken up by the program. ## ESP32S2 Programming @@ -75,7 +76,9 @@ It enumerates as 2 interfaces. If you want to mess with the programming code in Windows, you will have to install WinUSB to the interface 0. Then you can uninstall it in Device Manager under USB Devices. -On linux you find the serial port with `ls -l /dev/ttyUSB* /dev/ttyACM*` and connect to it with `screen /dev/ttyACM0 115200` +On linux you find the serial port with `ls -l /dev/ttyUSB* /dev/ttyACM*` and connect to it with `screen /dev/ttyACM0 115200` +Disconnect with `CTRL+a` `:quit`. + Adding your user to these groups will remove the need to `sudo` for access to the serial port: debian-based `sudo usermod -a -G dialout $USER` @@ -106,8 +109,19 @@ To use the WCH-Link in WSL, it is required to "attach" the USB hardware on the W 6. In powershell, use the command `usbipd wsl attach --busid=<BUSID>` to attach the device at the busid from previous step 7. You will hear the windows sound for the USB device being removed (and silently attached to WSL instead) 8. In WSL, you will now be able to run `lsusb` and see that the SCH-Link is attached -9. For unknown reasons, you must run make under root access in order to connect to the programmer with minichlink. Recommend running `sudo make flash` when building and programming projects using WSL -Feel free to solve this issue and figure out a way to give the user hardware access to WCH-Link and modify these instructions. +9. For unknown reasons, you must run make under root access in order to connect to the programmer with minichlink. Recommend running `sudo make` when building and programming projects using WSL. This may work too (to be confirmed): + +### non-root access on linux +Unlike serial interfaces, by default, the USB device is owned by root, has group set to root and everyone else may only read. +1. Get the vendor:device ID of the WCH-Link from `lsusb`. +2. Create a udev rule with `sudo nano /etc/udev/rules.d/80-USB_WCH-Link.rules`, paste (CTRL+SHIFT+V) `SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="8010", MODE="0666"` and save, replacing the idVendor and idProduct if what you got previously was different. +3. Reboot or reload the udev rules with `sudo udevadm control --reload-rules && sudo udevadm trigger` +4. ??? +5. profit +Now anyone on your PC has access to the WCH-Link device, so you can stop using sudo for make. +I don't think there are any security risks here. +You may also tie this to the WCH-Link serial number or some other attribute from `udevadm info -a -n /dev/bus/usb/busid/deviceid` with the bus id and device id you got from lsusb earlier. + ## minichlink diff --git a/examples/spi_24L01_rx/Makefile b/examples/spi_24L01_rx/Makefile index ee2bc6df165c54973ce8d7028a83128d7ce7eaef..5b54c64b56f41e500746d29d60f3dc740ad132dc 100644 --- a/examples/spi_24L01_rx/Makefile +++ b/examples/spi_24L01_rx/Makefile @@ -1,11 +1,11 @@ +all : flash + TARGET:=spi_24L01_rx -ADDITIONAL_C_FILES+=SPI.c nrf24l01_low_level.c nrf24l01.c +ADDITIONAL_C_FILES+=nrf24l01_low_level.c nrf24l01.c CFLAGS+=-DSTDOUT_UART include ../../ch32v003fun/ch32v003fun.mk -all : flash flash : cv_flash clean : cv_clean - diff --git a/examples/spi_24L01_rx/NRF24L01_RX_Arduino/NRF24L01_RX_Arduino.ino b/examples/spi_24L01_rx/NRF24L01_RX_Arduino/NRF24L01_RX_Arduino.ino index a032f5e5bbcc4668ca7b77a1ff0adc63dab74b73..df2beaa215a0a1211577952329e5f1716d1701d8 100644 --- a/examples/spi_24L01_rx/NRF24L01_RX_Arduino/NRF24L01_RX_Arduino.ino +++ b/examples/spi_24L01_rx/NRF24L01_RX_Arduino/NRF24L01_RX_Arduino.ino @@ -5,12 +5,16 @@ extern "C"{ #include "nrf24l01.h" } -#define TIME_GAP 300 + +#define TIME_GAP 300 uint8_t ascending_number = 0; char txt[16]; + +//######### debug fn + void uint8_to_binary_string(uint8_t value, char* output, int len) { for (int i = 0; i < len; i++) { output[len - i - 1] = (value & 1) ? '1' : '0'; @@ -40,6 +44,10 @@ void print_debug() { print_reg("EN_RXADDR ", EN_RXADDR_ADDRESS); } + + +//######### LED fn + //LED_BUILTIN is pin 13 is SCK of SPI, already using that void led_on() { digitalWrite(4, HIGH); @@ -51,6 +59,8 @@ void led_off() { +//######### RX fn + uint8_t recvnumber() { return nrf24_receive(&ascending_number, 1); } @@ -90,18 +100,17 @@ void receive() { } +//######### MAIN + void setup() { Serial.begin(115200); - Serial.println("\n\n\n kys!\n"); - Serial.print("\r\r\n\nspi_24L01_RX\n\r"); Serial.print("initializing radio as RX..."); nrf24_device(RECEIVER, RESET); //initializing nrf24l01+ as a receiver device with one simple function call nrf24_rf_power(18); //default TX power is -6dB, pretty strong, reduce to -18dBm for one room (ACK = TX) - Serial.println("done"); pinMode(4, OUTPUT); diff --git a/examples/spi_24L01_rx/NRF24L01_RX_Arduino/nrf24l01.c b/examples/spi_24L01_rx/NRF24L01_RX_Arduino/nrf24l01.c index fadd28d0e5a3055f77bdc1081ea370be27024ff3..9f3b0e34c9b3849e16b42e55a9cb245b32e55c83 100644 --- a/examples/spi_24L01_rx/NRF24L01_RX_Arduino/nrf24l01.c +++ b/examples/spi_24L01_rx/NRF24L01_RX_Arduino/nrf24l01.c @@ -1,8 +1,9 @@ #include "nrf24l01.h" -uint8_t NRF24_en_ack = ENABLE; -uint8_t NRF24_en_dynamic_payload = ENABLE; - +/*nRF24L01+ features, enable / disable as needed*/ +static uint8_t NRF24_en_ack = ENABLE; +static uint8_t NRF24_en_no_ack = ENABLE; +static uint8_t NRF24_en_dynamic_payload = ENABLE; /*global variables related to this file*/ static uint8_t SPI_command; /*1 byte spi command*/ @@ -13,7 +14,7 @@ static uint8_t current_address_width; /*current addr static uint8_t reset_flag = 0; /*reset flag lets the software know if the nrf24l01+ has ever been reset or not*/ static uint8_t current_mode = DEVICE_NOT_INITIALIZED; /*current mode of operation: DEVICE_NOT_INITIALIZED, PRX, PTX, STANDBYI, STANDBYII, POWER_DOWN*/ static uint8_t current_payload_width; /*payload width could be from 1 to 32 bytes, in either dynamic or static forms*/ -static uint8_t current_acknowledgement_state = NO_ACK_MODE; +static uint8_t current_acknowledgement_state = NO_ACK_MODE; /*2 dimensional array of pipe addresses (5 byte address width) by default. you can change addresses using a new array later. Pipe 1 address could be anything. pipe 3 to 6 addresses share the first 4 bytes with pipe 2 and only differ in byte 5*/ @@ -26,42 +27,6 @@ uint8_t datapipe_address[MAXIMUM_NUMBER_OF_DATAPIPES][ADDRESS_WIDTH_DEFAULT] = { {0X20, 0XC3, 0XC2, 0XC1, 0XA5} }; -/*function to enable or disable sending without acknowledge. - if disabled, you cannot disable acknowledging a payload. manipulates EN_DYN_ACK inside FEATURE*/ -void nrf24_payload_without_ack(uint8_t state) -{ - nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); - if (state == ENABLE) - { - register_new_value = register_current_value | (1 << EN_DYN_ACK); - } - else - { - register_new_value = register_current_value & (~(1 << EN_DYN_ACK)); - } - nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); -} - -void nrf24_payload_with_ack(uint8_t state) { - if (state == ENABLE) - { - nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); - register_new_value = register_current_value | (1 << EN_ACK_PAY) | (1 << EN_DPL); - nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); - nrf24_read(DYNPD_ADDRESS, ®ister_current_value, 1, CLOSE); - register_new_value = register_current_value | 0b111111; - nrf24_write(DYNPD_ADDRESS, ®ister_new_value, 1, CLOSE); - } - else - { - nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); - register_new_value = register_current_value & (~((1 << EN_ACK_PAY) | (1 << EN_DPL))); - nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); - } -} - - - /*function for PTX device to transmit 1 to 32 bytes of data, used for both dynamic payload length and static payload length methods. acknowledgemet state could be NO_ACK_MODE or ACK_MODE*/ uint8_t nrf24_transmit(uint8_t *payload, uint8_t payload_width, uint8_t acknowledgement_state) @@ -72,7 +37,7 @@ uint8_t nrf24_transmit(uint8_t *payload, uint8_t payload_width, uint8_t acknowle current_acknowledgement_state = acknowledgement_state; /*setting the acknowledgement state to either NO_ACK or ACK, based on input*/ if (NRF24_en_dynamic_payload == ENABLE) current_payload_width = payload_width; - nrf24_send_payload(payload, current_payload_width); /*the actual function to send data*/ + nrf24_send_payload(payload, payload_width); /*the actual function to send data*/ return (TRANSMIT_BEGIN); /*TX FIFO is not full and nrf24l01+ mode is standby ii or ptx*/ } else @@ -102,24 +67,6 @@ void nrf24_send_payload(uint8_t *payload, uint8_t payload_width) /*reports back transmit status: TRANSMIT_DONE, TRANSMIT_FAILED (in case of reaching maximum number of retransmits in auto acknowledgement mode) and TRANSMIT_IN_PROGRESS, if neither flags are set. automatically resets the '1' flags.*/ uint8_t nrf24_transmit_status() -{ - nrf24_read(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*status register is read to check TX_DS flag*/ - if (register_current_value & (1 << TX_DS)) /*if the TX_DS == 1, */ - { - nrf24_write(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*reseting the TX_DS flag. as mentioned by datasheet, writing '1' to a flag resets that flag*/ - return TRANSMIT_DONE; - } - else if (register_current_value & (1 << MAX_RT)) - { - nrf24_write(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*reseting the MAX_RT flag. as mentioned by datasheet, writing '1' to a flag resets that flag*/ - nrf24_flush(TX_BUFFER); - return TRANSMIT_FAILED; - } - else - return TRANSMIT_IN_PROGRESS; -} - -uint8_t nrf24_transmit_status_clear() { nrf24_read(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*status register is read to check TX_DS flag*/ if (register_current_value & (1 << TX_DS)) /*if the TX_DS == 1, */ @@ -213,7 +160,7 @@ uint8_t nrf24_flush(uint8_t fifo_select) /*must be called atleast once, which happens with calling nrf24_device function*/ void nrf24_reset() { - reset_flag = 1; + reset_flag = RESET; nrf24_CE(CE_OFF); register_new_value = CONFIG_REGISTER_DEFAULT; nrf24_write(CONFIG_ADDRESS, ®ister_new_value, 1, CLOSE); @@ -252,7 +199,7 @@ void nrf24_reset() nrf24_automatic_retransmit_setup(RETRANSMIT_DELAY_DEFAULT, RETRANSMIT_COUNT_DEFAULT); nrf24_auto_acknowledgment_setup(NUMBER_OF_DP_DEFAULT); nrf24_dynamic_payload(NRF24_en_dynamic_payload, NUMBER_OF_DP_DEFAULT); - nrf24_payload_without_ack(ENABLE); + nrf24_payload_without_ack(NRF24_en_no_ack); nrf24_payload_with_ack(NRF24_en_ack); } @@ -316,11 +263,8 @@ void nrf24_automatic_retransmit_setup(uint16_t delay_time, uint8_t retransmit_co /*setting auto acknoledgement on datapipes*/ void nrf24_auto_acknowledgment_setup(uint8_t datapipe) { - /* if (datapipe < 7) register_new_value = (1 << datapipe) - 1; - */ - register_new_value = EN_AA_REGISTER_DEFAULT; nrf24_write(EN_AA_ADDRESS, ®ister_new_value, 1, CLOSE); } @@ -336,11 +280,55 @@ void nrf24_dynamic_payload(uint8_t state, uint8_t datapipe) if (datapipe < 7) register_new_value = (1 << datapipe) - 1; /*turning on dynamic payload width on chosen datapipes, using DYNPD register*/ nrf24_write(DYNPD_ADDRESS, ®ister_new_value, 1, CLOSE); + NRF24_en_dynamic_payload = ENABLE; } else { register_new_value = register_current_value & (~(1 << EN_DPL)); nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + NRF24_en_dynamic_payload = DISABLE; + } +} + +/*function to enable or disable sending without acknowledge. + if disabled, TX must send a payload with ACK-request and receiver must be able to answer it. + manipulates EN_DYN_ACK inside FEATURE*/ +void nrf24_payload_without_ack(uint8_t state) +{ + if (state == ENABLE) + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value | (1 << EN_DYN_ACK); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + } + else + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value & (~(1 << EN_DYN_ACK)); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + } +} + +/*function to enable or disable sending with acknowledge. + if disabled, the payload can be sent only without ACK-request. + manipulates EN_ACK_PAY and EN_DPL inside FEATURE as Dynamic Payload Length is required.*/ +void nrf24_payload_with_ack(uint8_t state) +{ + if (state == ENABLE) + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value | (1 << EN_ACK_PAY) | (1 << EN_DPL); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + nrf24_read(DYNPD_ADDRESS, ®ister_current_value, 1, CLOSE); + // enable dynamic payload for all pipes + register_new_value = register_current_value | 0b111111; + nrf24_write(DYNPD_ADDRESS, ®ister_new_value, 1, CLOSE); + } + else + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value & (~((1 << EN_ACK_PAY) | (1 << EN_DPL))); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); } } @@ -447,6 +435,58 @@ void nrf24_rf_power(uint8_t rf_power) nrf24_write(RF_SETUP_ADDRESS, ®ister_new_value, 1, CLOSE); } +/*read whether the current channel is busy (has traffic), needs to be called from RX mode*/ +uint8_t nrf24_rf_channel_read_busy(uint8_t rf_channel) +{ + uint8_t signals_detected; + nrf24_read(RPD_REG_ADDRESS, &signals_detected, 1, CLOSE); + if (signals_detected) { + return CHANNEL_BUSY; + } + else { + return CHANNEL_CLEAR; + } +} + +/*test whether a channel is busy (has traffic), waiting for ms_to_test*/ +uint8_t nrf24_rf_channel_test_busy(uint8_t rf_channel, uint16_t ms_to_test) +{ + if ((rf_channel <= 125) && (rf_channel >= 1)) + { + // back up old channel + uint8_t previous_channel; + nrf24_read(RF_CH_ADDRESS, &previous_channel, 1, CLOSE); + // back up old mode + uint8_t previous_mode = current_mode; + // switch to new channel + nrf24_rf_channel(rf_channel); + // switch to RX, Received Power Detector is set to 0 and begins sampling + if (previous_mode != PRX) { + nrf24_mode(PRX); + } + // wait at least 1 ms before declaring channel clear + delay_function(1 > ms_to_test ? 1 : ms_to_test); + // Received Power Detector latches to 1 if there was a signal >-64dBm for at least 40 uS consecutively since RX mode was enabled + uint8_t signals_detected = nrf24_rf_channel_read_busy(rf_channel); + // switch back to old channel + nrf24_rf_channel(previous_channel); + // switch back to old mode + if (previous_mode != PRX) { + nrf24_mode(previous_mode); + } + if (signals_detected) { + return CHANNEL_BUSY; + } + else { + return CHANNEL_CLEAR; + } + } + else + { + return CHANNEL_BUSY; + } +} + /*nrf24l01+ RF channel selection, from 1 to 125*/ void nrf24_rf_channel(uint8_t rf_channel) { diff --git a/examples/spi_24L01_rx/NRF24L01_RX_Arduino/nrf24l01.h b/examples/spi_24L01_rx/NRF24L01_RX_Arduino/nrf24l01.h index 89d4b60f4a68fec76769922e59ef275f4d61679c..20876f691b44710ef4d034c78458623cbed827dc 100644 --- a/examples/spi_24L01_rx/NRF24L01_RX_Arduino/nrf24l01.h +++ b/examples/spi_24L01_rx/NRF24L01_RX_Arduino/nrf24l01.h @@ -4,10 +4,6 @@ #include <stdio.h> #include <stdint.h> - - - - #define STARTUP_DELAY 150 /*in milliseconds*/ #define POWER_DOWN_DELAY 2 #define STANDBYI_DELAY 2 @@ -66,6 +62,9 @@ #define RECEIVE_FIFO_EMPTY 2 #define TX_BUFFER 1 #define RX_BUFFER 0 +// return states for nrf24_rf_channel_test_busy +#define CHANNEL_CLEAR 0 +#define CHANNEL_BUSY 1 /*bits definition section*/ #define MASK_RX_DR 6 /*mask interrupt caused by RX_DR: 1 interrupt not reflected on IRQ pin (IRQ is active low), inside CONFIG register*/ @@ -116,7 +115,6 @@ #define RX_P_NO_2 3 #define RX_P_NO_1 2 #define RX_P_NO_0 1 -//#define TX_FULL 0 #define PLOS_CNT_3 7 /*inside OBSERVE_TX register, counts the total number of retransmissions since last channel change. reset by writing to RF_CH*/ #define PLOS_CNT_2 6 #define PLOS_CNT_1 5 @@ -191,6 +189,8 @@ void nrf24_mode(uint8_t mode); void nrf24_SPI(uint8_t input); void nrf24_CE(uint8_t input); void nrf24_address_width(uint8_t address_width); +uint8_t nrf24_rf_channel_read_busy(uint8_t rf_channel); +uint8_t nrf24_rf_channel_test_busy(uint8_t rf_channel, uint16_t ms_to_test); void nrf24_rf_channel(uint8_t rf_channel); void nrf24_rf_power(uint8_t rf_power); void nrf24_rf_datarate(uint16_t rf_datarate); @@ -205,6 +205,8 @@ void nrf24_datapipe_address_configuration(); void nrf24_datapipe_ptx(uint8_t datapipe_number); void nrf24_automatic_retransmit_setup(uint16_t delay_time, uint8_t retransmit_count); void nrf24_auto_acknowledgment_setup(uint8_t datapipe); +void nrf24_payload_without_ack(uint8_t state); +void nrf24_payload_with_ack(uint8_t state); void nrf24_dynamic_payload(uint8_t state, uint8_t datapipe); void nrf24_device(uint8_t device_mode, uint8_t reset_state); void nrf24_send_payload(uint8_t *payload, uint8_t payload_width); diff --git a/examples/spi_24L01_rx/SPI.h b/examples/spi_24L01_rx/SPI.h deleted file mode 100644 index 04898e2ee02cd69bc7fa8887799f78dd755d612b..0000000000000000000000000000000000000000 --- a/examples/spi_24L01_rx/SPI.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef SPI_H -#define SPI_H - -#include<stdint.h> //uintN_t support -#include"../../ch32v003fun/ch32v003fun.h" - -#define MIN(a,b) (((a)<(b))?(a):(b)) -#define MAX(a,b) (((a)>(b))?(a):(b)) - - -void SPI_poweron(); - -void kill_interrrupts(); -void restore_interrupts(); - -/* clock polarity and phase -CPOL leading trailing CPHA sample on -0 rising falling 0 leading -0 rising falling 1 trailing -1 falling rising 0 leading -1 falling rising 1 trailing -*/ -enum SPI_clk_modes{ - SPI_clk_mode_pol0_pha0_default, - SPI_clk_mode_pol0_pha1, - SPI_clk_mode_pol1_pha0, - SPI_clk_mode_pol1_pha1, -}; - -enum SPI_data_directions { - SPI_data_direction_2line_TxRx, // RX + TX 2-line bidirectional - SPI_data_direction_2line_Rx, // RX 2-line bidirectional - SPI_data_direction_1line_Rx, // RX 1-line unidirectional - SPI_data_direction_1line_Tx, // TX 1-line unidirectional -}; - -enum SPI_NSS_options { - SPI_NSS_hardware_PC0_default, // _NSS - SPI_NSS_hardware_PC1, // NSS but clashes with I2C SDA - SPI_NSS_software_PC3, - SPI_NSS_software_PC4, - SPI_NSS_software_any_manual, -}; - - -void SPI_NSS_software_high(); -void SPI_NSS_software_low(); - -void SPI_init( - uint32_t speedHz, - enum SPI_clk_modes clockMode, - enum SPI_data_directions dataDirection, - enum SPI_NSS_options NSSmode); -void SPI_begin_8(); -void SPI_begin_16(); -void SPI_end(); - - -void SPI_wait_TX_complete(); -uint8_t SPI_is_RX_empty(); -void SPI_wait_RX_available(); - - -void SPI_write_8(uint8_t data); -void SPI_write_16(uint16_t data); -uint8_t SPI_read_8(); -uint16_t SPI_read_16(); - - -uint8_t SPI_transfer_8(uint8_t data); -uint8_t SPI_transfer_16(uint16_t data); - - -void SPI_poweroff(); - - -#endif // SPI_H diff --git a/examples/spi_24L01_rx/SPI.c b/examples/spi_24L01_rx/ch32v003_SPI.h similarity index 63% rename from examples/spi_24L01_rx/SPI.c rename to examples/spi_24L01_rx/ch32v003_SPI.h index 90493b6217c8d1c81cc497f2a3a85e8514cdd063..786c230d29b0efc6ee0bf64703378ff3ba69cf46 100644 --- a/examples/spi_24L01_rx/SPI.c +++ b/examples/spi_24L01_rx/ch32v003_SPI.h @@ -1,69 +1,110 @@ -#include "SPI.h" +// you'll need to #define CH32V003_SPI_IMPLEMENTATION in the .c files that use this library. +// include guards +#ifndef CH32V003_SPI_H +#define CH32V003_SPI_H +// includes +#include<stdint.h> //uintN_t support +#include"../../ch32v003fun/ch32v003fun.h" -enum SPI_NSS_options NSS_selected; -uint16_t EXT1_INTENR_backup; +//######### SPI configuration states, use these for init() +// SPI peripheral config options +/* clock polarity and phase +CPOL leading trailing CPHA sample on +0 rising falling 0 leading +0 rising falling 1 trailing +1 falling rising 0 leading +1 falling rising 1 trailing +*/ +enum SPI_clk_modes{ + SPI_clk_mode_pol0_pha0_default, + SPI_clk_mode_pol0_pha1, + SPI_clk_mode_pol1_pha0, + SPI_clk_mode_pol1_pha1, +}; +enum SPI_data_directions { + SPI_data_direction_2line_TxRx, // RX + TX 2-line bidirectional + SPI_data_direction_2line_Rx, // RX 2-line bidirectional + SPI_data_direction_1line_Rx, // RX 1-line unidirectional + SPI_data_direction_1line_Tx, // TX 1-line unidirectional +}; +enum SPI_NSS_options { + SPI_NSS_hardware_PC0_default, // _NSS + SPI_NSS_hardware_PC1, // NSS but clashes with I2C SDA + SPI_NSS_software_PC3, + SPI_NSS_software_PC4, + SPI_NSS_software_any_manual, +}; + + + +//######### public function declarations, use these! +// initialize and configure the SPI peripheral +void SPI_init( + uint32_t speedHz, + enum SPI_clk_modes clockMode, + enum SPI_data_directions dataDirection, + enum SPI_NSS_options NSSmode); -void SPI_poweron() { - RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1; -} +// establish / end a connection to the SPI device +void SPI_begin_8(); +void SPI_begin_16(); +void SPI_end(); +// manually set the NSS pin high / low +void SPI_NSS_software_high(); +void SPI_NSS_software_low(); +// read / write the SPI device +// these commands are raw, you'll have to consider all other steps in SPI_transfer! +uint8_t SPI_read_8(); +uint16_t SPI_read_16(); +void SPI_write_8(uint8_t data); +void SPI_write_16(uint16_t data); -void kill_interrrupts() { - EXT1_INTENR_backup = EXTI->INTENR; - // zero the interrupt enable register to disable all interrupts - EXTI->INTENR = 0; -} +// send a command and get a response from the SPI device +// you'll use this for most devices +uint8_t SPI_transfer_8(uint8_t data); +uint8_t SPI_transfer_16(uint16_t data); -void restore_interrupts() { - EXTI->INTENR = EXT1_INTENR_backup; -} +// SPI peripheral power enable / disable (default off, init() automatically enables) +// send SPI peripheral to sleep +void SPI_poweroff(); +// wake SPI peripheral from sleep +void SPI_poweron(); +// helper: kill / restore all interrupts on the CH32V003 +void kill_interrrupts(); +void restore_interrupts(); -/* clock polarity and phase -CPOL leading trailing CPHA sample on -0 rising falling 0 leading -0 rising falling 1 trailing -1 falling rising 0 leading -1 falling rising 1 trailing -*/ -// software NSS output high -void SPI_NSS_software_high() { - switch (NSS_selected) { - case SPI_NSS_software_PC3: - GPIOC->BSHR |= (1<<3); - break; - case SPI_NSS_software_PC4: - GPIOC->BSHR |= (1<<4); - break; - default: - break; - } -} -// software NSS output low -void SPI_NSS_software_low() { - switch (NSS_selected) { - case SPI_NSS_software_PC3: - GPIOC->BSHR &= ~(1<<(16+3)); - break; - case SPI_NSS_software_PC4: - GPIOC->BSHR &= ~(1<<(16+4)); - break; - default: - break; - } -} +//############ h-file-only implementation section +// you'll need to #define CH32V003_SPI_IMPLEMENTATION in the .c files that use this library. +//#define CH32V003_SPI_IMPLEMENTATION //enable here so LSP can give you text colors while working on this library, disable for normal use of the library +#ifdef CH32V003_SPI_IMPLEMENTATION + + +//######### internal function declarations +static inline void SPI_wait_TX_complete(); +static inline uint8_t SPI_is_RX_empty(); +static inline void SPI_wait_RX_available(); +// min and max helper macros +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) +//######### internal variables +static enum SPI_NSS_options NSS_selected; +static uint16_t EXT1_INTENR_backup; + +//######### public function definitions void SPI_init( uint32_t speedHz, enum SPI_clk_modes clockMode, @@ -169,54 +210,53 @@ void SPI_begin_8() { SPI1->CTLR1 |= SPI_DataSize_8b; // DFF 16bit data-length enable, writable only when SPE is 0 SPI1->CTLR1 |= CTLR1_SPE_Set; } - void SPI_begin_16() { SPI1->CTLR1 |= SPI_DataSize_16b; // DFF 16bit data-length enable, writable only when SPE is 0 SPI1->CTLR1 |= CTLR1_SPE_Set; } - void SPI_end() { SPI1->CTLR1 &= CTLR1_SPE_Reset; } - - -void SPI_wait_TX_complete() { - while(!(SPI1->STATR & SPI_STATR_TXE)) { - asm volatile("nop"); +// software NSS output high +void SPI_NSS_software_high() { + switch (NSS_selected) { + case SPI_NSS_software_PC3: + GPIOC->BSHR |= (1<<3); + break; + case SPI_NSS_software_PC4: + GPIOC->BSHR |= (1<<4); + break; + default: + break; } } - -uint8_t SPI_is_RX_empty() { - return SPI1->STATR & SPI_STATR_RXNE; -} - -void SPI_wait_RX_available() { - while(!(SPI1->STATR & SPI_STATR_RXNE)) { - asm volatile("nop"); +// software NSS output low +void SPI_NSS_software_low() { + switch (NSS_selected) { + case SPI_NSS_software_PC3: + GPIOC->BSHR &= ~(1<<(16+3)); + break; + case SPI_NSS_software_PC4: + GPIOC->BSHR &= ~(1<<(16+4)); + break; + default: + break; } } - - -void SPI_write_8(uint8_t data) { - SPI1->DATAR = data; -} - -void SPI_write_16(uint16_t data) { - SPI1->DATAR = data; -} - uint8_t SPI_read_8() { return SPI1->DATAR; } - uint16_t SPI_read_16() { return SPI1->DATAR; } - - - +void SPI_write_8(uint8_t data) { + SPI1->DATAR = data; +} +void SPI_write_16(uint16_t data) { + SPI1->DATAR = data; +} uint8_t SPI_transfer_8(uint8_t data) { SPI_NSS_software_high(); SPI_write_8(data); @@ -226,7 +266,6 @@ uint8_t SPI_transfer_8(uint8_t data) { SPI_NSS_software_low(); return SPI_read_8(); } - uint8_t SPI_transfer_16(uint16_t data) { SPI_NSS_software_high(); SPI_write_16(data); @@ -237,10 +276,40 @@ uint8_t SPI_transfer_16(uint16_t data) { return SPI_read_16(); } - - void SPI_poweroff() { SPI_end(); RCC->APB2PCENR &= ~RCC_APB2Periph_SPI1; } +void SPI_poweron() { + RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1; +} + +void kill_interrrupts() { + EXT1_INTENR_backup = EXTI->INTENR; + // zero the interrupt enable register to disable all interrupts + EXTI->INTENR = 0; +} +void restore_interrupts() { + EXTI->INTENR = EXT1_INTENR_backup; +} + + + +//######### internal function definitions + +static void SPI_wait_TX_complete() { + while(!(SPI1->STATR & SPI_STATR_TXE)) { + asm volatile("nop"); + } +} +static uint8_t SPI_is_RX_empty() { + return SPI1->STATR & SPI_STATR_RXNE; +} +static void SPI_wait_RX_available() { + while(!(SPI1->STATR & SPI_STATR_RXNE)) { + asm volatile("nop"); + } +} +#endif // CH32V003_SPI_IMPLEMENTATION +#endif // CH32V003_SPI_H diff --git a/examples/spi_24L01_rx/nrf24l01.c b/examples/spi_24L01_rx/nrf24l01.c index fadd28d0e5a3055f77bdc1081ea370be27024ff3..9f3b0e34c9b3849e16b42e55a9cb245b32e55c83 100644 --- a/examples/spi_24L01_rx/nrf24l01.c +++ b/examples/spi_24L01_rx/nrf24l01.c @@ -1,8 +1,9 @@ #include "nrf24l01.h" -uint8_t NRF24_en_ack = ENABLE; -uint8_t NRF24_en_dynamic_payload = ENABLE; - +/*nRF24L01+ features, enable / disable as needed*/ +static uint8_t NRF24_en_ack = ENABLE; +static uint8_t NRF24_en_no_ack = ENABLE; +static uint8_t NRF24_en_dynamic_payload = ENABLE; /*global variables related to this file*/ static uint8_t SPI_command; /*1 byte spi command*/ @@ -13,7 +14,7 @@ static uint8_t current_address_width; /*current addr static uint8_t reset_flag = 0; /*reset flag lets the software know if the nrf24l01+ has ever been reset or not*/ static uint8_t current_mode = DEVICE_NOT_INITIALIZED; /*current mode of operation: DEVICE_NOT_INITIALIZED, PRX, PTX, STANDBYI, STANDBYII, POWER_DOWN*/ static uint8_t current_payload_width; /*payload width could be from 1 to 32 bytes, in either dynamic or static forms*/ -static uint8_t current_acknowledgement_state = NO_ACK_MODE; +static uint8_t current_acknowledgement_state = NO_ACK_MODE; /*2 dimensional array of pipe addresses (5 byte address width) by default. you can change addresses using a new array later. Pipe 1 address could be anything. pipe 3 to 6 addresses share the first 4 bytes with pipe 2 and only differ in byte 5*/ @@ -26,42 +27,6 @@ uint8_t datapipe_address[MAXIMUM_NUMBER_OF_DATAPIPES][ADDRESS_WIDTH_DEFAULT] = { {0X20, 0XC3, 0XC2, 0XC1, 0XA5} }; -/*function to enable or disable sending without acknowledge. - if disabled, you cannot disable acknowledging a payload. manipulates EN_DYN_ACK inside FEATURE*/ -void nrf24_payload_without_ack(uint8_t state) -{ - nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); - if (state == ENABLE) - { - register_new_value = register_current_value | (1 << EN_DYN_ACK); - } - else - { - register_new_value = register_current_value & (~(1 << EN_DYN_ACK)); - } - nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); -} - -void nrf24_payload_with_ack(uint8_t state) { - if (state == ENABLE) - { - nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); - register_new_value = register_current_value | (1 << EN_ACK_PAY) | (1 << EN_DPL); - nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); - nrf24_read(DYNPD_ADDRESS, ®ister_current_value, 1, CLOSE); - register_new_value = register_current_value | 0b111111; - nrf24_write(DYNPD_ADDRESS, ®ister_new_value, 1, CLOSE); - } - else - { - nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); - register_new_value = register_current_value & (~((1 << EN_ACK_PAY) | (1 << EN_DPL))); - nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); - } -} - - - /*function for PTX device to transmit 1 to 32 bytes of data, used for both dynamic payload length and static payload length methods. acknowledgemet state could be NO_ACK_MODE or ACK_MODE*/ uint8_t nrf24_transmit(uint8_t *payload, uint8_t payload_width, uint8_t acknowledgement_state) @@ -72,7 +37,7 @@ uint8_t nrf24_transmit(uint8_t *payload, uint8_t payload_width, uint8_t acknowle current_acknowledgement_state = acknowledgement_state; /*setting the acknowledgement state to either NO_ACK or ACK, based on input*/ if (NRF24_en_dynamic_payload == ENABLE) current_payload_width = payload_width; - nrf24_send_payload(payload, current_payload_width); /*the actual function to send data*/ + nrf24_send_payload(payload, payload_width); /*the actual function to send data*/ return (TRANSMIT_BEGIN); /*TX FIFO is not full and nrf24l01+ mode is standby ii or ptx*/ } else @@ -102,24 +67,6 @@ void nrf24_send_payload(uint8_t *payload, uint8_t payload_width) /*reports back transmit status: TRANSMIT_DONE, TRANSMIT_FAILED (in case of reaching maximum number of retransmits in auto acknowledgement mode) and TRANSMIT_IN_PROGRESS, if neither flags are set. automatically resets the '1' flags.*/ uint8_t nrf24_transmit_status() -{ - nrf24_read(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*status register is read to check TX_DS flag*/ - if (register_current_value & (1 << TX_DS)) /*if the TX_DS == 1, */ - { - nrf24_write(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*reseting the TX_DS flag. as mentioned by datasheet, writing '1' to a flag resets that flag*/ - return TRANSMIT_DONE; - } - else if (register_current_value & (1 << MAX_RT)) - { - nrf24_write(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*reseting the MAX_RT flag. as mentioned by datasheet, writing '1' to a flag resets that flag*/ - nrf24_flush(TX_BUFFER); - return TRANSMIT_FAILED; - } - else - return TRANSMIT_IN_PROGRESS; -} - -uint8_t nrf24_transmit_status_clear() { nrf24_read(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*status register is read to check TX_DS flag*/ if (register_current_value & (1 << TX_DS)) /*if the TX_DS == 1, */ @@ -213,7 +160,7 @@ uint8_t nrf24_flush(uint8_t fifo_select) /*must be called atleast once, which happens with calling nrf24_device function*/ void nrf24_reset() { - reset_flag = 1; + reset_flag = RESET; nrf24_CE(CE_OFF); register_new_value = CONFIG_REGISTER_DEFAULT; nrf24_write(CONFIG_ADDRESS, ®ister_new_value, 1, CLOSE); @@ -252,7 +199,7 @@ void nrf24_reset() nrf24_automatic_retransmit_setup(RETRANSMIT_DELAY_DEFAULT, RETRANSMIT_COUNT_DEFAULT); nrf24_auto_acknowledgment_setup(NUMBER_OF_DP_DEFAULT); nrf24_dynamic_payload(NRF24_en_dynamic_payload, NUMBER_OF_DP_DEFAULT); - nrf24_payload_without_ack(ENABLE); + nrf24_payload_without_ack(NRF24_en_no_ack); nrf24_payload_with_ack(NRF24_en_ack); } @@ -316,11 +263,8 @@ void nrf24_automatic_retransmit_setup(uint16_t delay_time, uint8_t retransmit_co /*setting auto acknoledgement on datapipes*/ void nrf24_auto_acknowledgment_setup(uint8_t datapipe) { - /* if (datapipe < 7) register_new_value = (1 << datapipe) - 1; - */ - register_new_value = EN_AA_REGISTER_DEFAULT; nrf24_write(EN_AA_ADDRESS, ®ister_new_value, 1, CLOSE); } @@ -336,11 +280,55 @@ void nrf24_dynamic_payload(uint8_t state, uint8_t datapipe) if (datapipe < 7) register_new_value = (1 << datapipe) - 1; /*turning on dynamic payload width on chosen datapipes, using DYNPD register*/ nrf24_write(DYNPD_ADDRESS, ®ister_new_value, 1, CLOSE); + NRF24_en_dynamic_payload = ENABLE; } else { register_new_value = register_current_value & (~(1 << EN_DPL)); nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + NRF24_en_dynamic_payload = DISABLE; + } +} + +/*function to enable or disable sending without acknowledge. + if disabled, TX must send a payload with ACK-request and receiver must be able to answer it. + manipulates EN_DYN_ACK inside FEATURE*/ +void nrf24_payload_without_ack(uint8_t state) +{ + if (state == ENABLE) + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value | (1 << EN_DYN_ACK); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + } + else + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value & (~(1 << EN_DYN_ACK)); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + } +} + +/*function to enable or disable sending with acknowledge. + if disabled, the payload can be sent only without ACK-request. + manipulates EN_ACK_PAY and EN_DPL inside FEATURE as Dynamic Payload Length is required.*/ +void nrf24_payload_with_ack(uint8_t state) +{ + if (state == ENABLE) + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value | (1 << EN_ACK_PAY) | (1 << EN_DPL); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + nrf24_read(DYNPD_ADDRESS, ®ister_current_value, 1, CLOSE); + // enable dynamic payload for all pipes + register_new_value = register_current_value | 0b111111; + nrf24_write(DYNPD_ADDRESS, ®ister_new_value, 1, CLOSE); + } + else + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value & (~((1 << EN_ACK_PAY) | (1 << EN_DPL))); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); } } @@ -447,6 +435,58 @@ void nrf24_rf_power(uint8_t rf_power) nrf24_write(RF_SETUP_ADDRESS, ®ister_new_value, 1, CLOSE); } +/*read whether the current channel is busy (has traffic), needs to be called from RX mode*/ +uint8_t nrf24_rf_channel_read_busy(uint8_t rf_channel) +{ + uint8_t signals_detected; + nrf24_read(RPD_REG_ADDRESS, &signals_detected, 1, CLOSE); + if (signals_detected) { + return CHANNEL_BUSY; + } + else { + return CHANNEL_CLEAR; + } +} + +/*test whether a channel is busy (has traffic), waiting for ms_to_test*/ +uint8_t nrf24_rf_channel_test_busy(uint8_t rf_channel, uint16_t ms_to_test) +{ + if ((rf_channel <= 125) && (rf_channel >= 1)) + { + // back up old channel + uint8_t previous_channel; + nrf24_read(RF_CH_ADDRESS, &previous_channel, 1, CLOSE); + // back up old mode + uint8_t previous_mode = current_mode; + // switch to new channel + nrf24_rf_channel(rf_channel); + // switch to RX, Received Power Detector is set to 0 and begins sampling + if (previous_mode != PRX) { + nrf24_mode(PRX); + } + // wait at least 1 ms before declaring channel clear + delay_function(1 > ms_to_test ? 1 : ms_to_test); + // Received Power Detector latches to 1 if there was a signal >-64dBm for at least 40 uS consecutively since RX mode was enabled + uint8_t signals_detected = nrf24_rf_channel_read_busy(rf_channel); + // switch back to old channel + nrf24_rf_channel(previous_channel); + // switch back to old mode + if (previous_mode != PRX) { + nrf24_mode(previous_mode); + } + if (signals_detected) { + return CHANNEL_BUSY; + } + else { + return CHANNEL_CLEAR; + } + } + else + { + return CHANNEL_BUSY; + } +} + /*nrf24l01+ RF channel selection, from 1 to 125*/ void nrf24_rf_channel(uint8_t rf_channel) { diff --git a/examples/spi_24L01_rx/nrf24l01.h b/examples/spi_24L01_rx/nrf24l01.h index 89d4b60f4a68fec76769922e59ef275f4d61679c..20876f691b44710ef4d034c78458623cbed827dc 100644 --- a/examples/spi_24L01_rx/nrf24l01.h +++ b/examples/spi_24L01_rx/nrf24l01.h @@ -4,10 +4,6 @@ #include <stdio.h> #include <stdint.h> - - - - #define STARTUP_DELAY 150 /*in milliseconds*/ #define POWER_DOWN_DELAY 2 #define STANDBYI_DELAY 2 @@ -66,6 +62,9 @@ #define RECEIVE_FIFO_EMPTY 2 #define TX_BUFFER 1 #define RX_BUFFER 0 +// return states for nrf24_rf_channel_test_busy +#define CHANNEL_CLEAR 0 +#define CHANNEL_BUSY 1 /*bits definition section*/ #define MASK_RX_DR 6 /*mask interrupt caused by RX_DR: 1 interrupt not reflected on IRQ pin (IRQ is active low), inside CONFIG register*/ @@ -116,7 +115,6 @@ #define RX_P_NO_2 3 #define RX_P_NO_1 2 #define RX_P_NO_0 1 -//#define TX_FULL 0 #define PLOS_CNT_3 7 /*inside OBSERVE_TX register, counts the total number of retransmissions since last channel change. reset by writing to RF_CH*/ #define PLOS_CNT_2 6 #define PLOS_CNT_1 5 @@ -191,6 +189,8 @@ void nrf24_mode(uint8_t mode); void nrf24_SPI(uint8_t input); void nrf24_CE(uint8_t input); void nrf24_address_width(uint8_t address_width); +uint8_t nrf24_rf_channel_read_busy(uint8_t rf_channel); +uint8_t nrf24_rf_channel_test_busy(uint8_t rf_channel, uint16_t ms_to_test); void nrf24_rf_channel(uint8_t rf_channel); void nrf24_rf_power(uint8_t rf_power); void nrf24_rf_datarate(uint16_t rf_datarate); @@ -205,6 +205,8 @@ void nrf24_datapipe_address_configuration(); void nrf24_datapipe_ptx(uint8_t datapipe_number); void nrf24_automatic_retransmit_setup(uint16_t delay_time, uint8_t retransmit_count); void nrf24_auto_acknowledgment_setup(uint8_t datapipe); +void nrf24_payload_without_ack(uint8_t state); +void nrf24_payload_with_ack(uint8_t state); void nrf24_dynamic_payload(uint8_t state, uint8_t datapipe); void nrf24_device(uint8_t device_mode, uint8_t reset_state); void nrf24_send_payload(uint8_t *payload, uint8_t payload_width); diff --git a/examples/spi_24L01_rx/nrf24l01_low_level.c b/examples/spi_24L01_rx/nrf24l01_low_level.c index 2578b0da9b3331c94a0eb2e1a029be94a5e360cf..da886d6de07b00cf64a3262f11045bee79ebe3c7 100644 --- a/examples/spi_24L01_rx/nrf24l01_low_level.c +++ b/examples/spi_24L01_rx/nrf24l01_low_level.c @@ -2,8 +2,8 @@ #define APB_CLOCK SYSTEM_CORE_CLOCK #include "../../ch32v003fun/ch32v003fun.h" -#include "SPI.h" - +#define CH32V003_SPI_IMPLEMENTATION +#include "ch32v003_SPI.h" #include "nrf24l01.h" /*start of low level functions, specific to the mcu and compiler*/ diff --git a/examples/spi_24L01_rx/spi_24L01_rx.c b/examples/spi_24L01_rx/spi_24L01_rx.c index 8225f4451bca64e8baff1be8355abaaf853a2c11..1c648fa9e8f68a10bbb09008e01addcad93a57b2 100644 --- a/examples/spi_24L01_rx/spi_24L01_rx.c +++ b/examples/spi_24L01_rx/spi_24L01_rx.c @@ -3,8 +3,6 @@ * 04-26-2023 recallmenot */ -// Could be defined here, or in the processor defines. -#include <stdint.h> #define SYSTEM_CORE_CLOCK 48000000 #define APB_CLOCK SYSTEM_CORE_CLOCK @@ -12,14 +10,47 @@ #include <stdio.h> #include "nrf24l01.h" -#define TIME_GAP 300 + +#define TIME_GAP 300 uint8_t ascending_number = 0; char txt[16]; -// ####### start of main program ############################################################### +//######### debug fn + +void uint8_to_binary_string(uint8_t value, char* output, int len) { + for (int i = 0; i < len; i++) { + output[len - i - 1] = (value & 1) ? '1' : '0'; + value >>= 1; + } + output[len] = '\0'; +} + + +void print_reg(char* name, uint8_t addr) { + char str[9]; + uint8_t REG; + nrf24_read(addr, ®, 1, CLOSE); + uint8_to_binary_string(REG, str, 8); + printf(" %s register: %s\n\r", name, str); +} + + +void print_debug() { + print_reg("FEATURE ", FEATURE_ADDRESS); + print_reg("TX OBSERVE ", OBSERVE_TX_ADDRESS); + print_reg("STATUS ", STATUS_ADDRESS); + print_reg("RX_PW_P0 ADDR", RX_ADDR_P0_ADDRESS); + print_reg("TX ADDR ", TX_ADDR_ADDRESS); + print_reg("EN_AA ", EN_AA_ADDRESS); + print_reg("EN_RXADDR ", EN_RXADDR_ADDRESS); +} + + + +//######### LED fn // wire PD4 to LED1 on the dev board (-) void led_on() { @@ -32,6 +63,8 @@ void led_off() { +//######### RX fn + uint8_t recvnumber() { return nrf24_receive(&ascending_number, 1); } @@ -58,14 +91,18 @@ void receive() { case OPERATION_DONE: led_on(); // pick one of these two: - printf("*** RX success, received: %u\n\r", ascending_number); - //printf("*** RX success, received: %s\n\r", txt); + //printf("*** RX success, received: %u\n\r", ascending_number); + printf("*** RX success, received: %s\n\r", txt); led_off(); break; } Delay_Ms(TIME_GAP); } + + +//######### MAIN + int main() { SystemInit48HSI(); @@ -74,17 +111,22 @@ int main() SetupUART( UART_BRR ); Delay_Ms( 100 ); - // GPIO D0 Push-Pull for RX notification - RCC->APB2PCENR |= RCC_APB2Periph_GPIOD; - GPIOD->CFGLR &= ~(0xf<<(4*4)); - GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4); - printf("\r\r\n\nspi_24L01_RX\n\r"); printf("initializing radio as RX..."); nrf24_device(RECEIVER, RESET); + nrf24_rf_power(18); //default TX power is -6dB, pretty strong, reduce to -18dBm for one room (ACK = TX) printf("done.\n\r"); + print_debug(); + + // GPIO D0 Push-Pull for RX notification + RCC->APB2PCENR |= RCC_APB2Periph_GPIOD; + GPIOD->CFGLR &= ~(0xf<<(4*4)); + GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4); + + Delay_Ms(1000); + printf("looping...\n\r"); while(1) { diff --git a/examples/spi_24L01_tx/Makefile b/examples/spi_24L01_tx/Makefile index 1015df63235bed81eccd0269138c141e6f8e3563..6ad3d51350ca002205f5ad25ed107cfdf4086b2a 100644 --- a/examples/spi_24L01_tx/Makefile +++ b/examples/spi_24L01_tx/Makefile @@ -1,11 +1,11 @@ +all : flash + TARGET:=spi_24L01_tx -ADDITIONAL_C_FILES+=SPI.c nrf24l01_low_level.c nrf24l01.c +ADDITIONAL_C_FILES+=nrf24l01_low_level.c nrf24l01.c CFLAGS+=-DSTDOUT_UART include ../../ch32v003fun/ch32v003fun.mk -all : flash flash : cv_flash clean : cv_clean - diff --git a/examples/spi_24L01_tx/NRF24L01_TX_Arduino/NRF24L01_TX_Arduino.ino b/examples/spi_24L01_tx/NRF24L01_TX_Arduino/NRF24L01_TX_Arduino.ino index e47623d754d847bba61123dee39d710caeddd1d7..5ccd6804c8a6415670fec30539e3b32ad867c505 100644 --- a/examples/spi_24L01_tx/NRF24L01_TX_Arduino/NRF24L01_TX_Arduino.ino +++ b/examples/spi_24L01_tx/NRF24L01_TX_Arduino/NRF24L01_TX_Arduino.ino @@ -1,15 +1,20 @@ //transmitter code example, transmits an ascending number every TIME_GAP milliseconds in NO_ACK_MODE. can be switched to ACK_MODE //payload length of 1 or 16 byte, 1Mbps datarate, -6 dbm rf transmit power, channel 32 of 125 + extern "C"{ #include "nrf24l01.h" } -#define TIME_GAP 1000 + +#define TIME_GAP 1000 uint8_t ascending_number = 0; char txt[16]; + +//######### debug fn + void uint8_to_binary_string(uint8_t value, char* output, int len) { for (int i = 0; i < len; i++) { output[len - i - 1] = (value & 1) ? '1' : '0'; @@ -18,7 +23,6 @@ void uint8_to_binary_string(uint8_t value, char* output, int len) { output[len] = '\0'; } - void print_reg(char* name, uint8_t addr) { Serial.print(" "); Serial.print(name); @@ -42,6 +46,8 @@ void print_debug() { +//######### LED fn + //LED_BUILTIN is pin 13 is SCK of SPI, already using that void led_on() { digitalWrite(4, HIGH); @@ -52,6 +58,7 @@ void led_off() { } +//######### TX fn uint8_t sendnumber() { return nrf24_transmit(&ascending_number, 1, ACK_MODE); @@ -97,22 +104,25 @@ void send() { +//######### MAIN void setup() { - Serial.begin(115200); - - pinMode(4, OUTPUT); + Serial.begin(115200); Serial.print("\r\r\n\nspi_24L01_TX\n\r"); Serial.print("initializing radio as TX..."); nrf24_device(TRANSMITTER, RESET); //initializing nrf24l01+ as a transmitter using one simple function - nrf24_rf_power(18) //default TX power is -6dB, pretty strong, reduce to -18dBm for one room + nrf24_rf_power(18); //default TX power is -6dB, pretty strong, reduce to -18dBm for one room Serial.print("done.\n\r"); + pinMode(4, OUTPUT); + print_debug(); + delay(1000); + Serial.print("entering loop\n\r"); } diff --git a/examples/spi_24L01_tx/NRF24L01_TX_Arduino/nrf24l01.c b/examples/spi_24L01_tx/NRF24L01_TX_Arduino/nrf24l01.c index fadd28d0e5a3055f77bdc1081ea370be27024ff3..9f3b0e34c9b3849e16b42e55a9cb245b32e55c83 100644 --- a/examples/spi_24L01_tx/NRF24L01_TX_Arduino/nrf24l01.c +++ b/examples/spi_24L01_tx/NRF24L01_TX_Arduino/nrf24l01.c @@ -1,8 +1,9 @@ #include "nrf24l01.h" -uint8_t NRF24_en_ack = ENABLE; -uint8_t NRF24_en_dynamic_payload = ENABLE; - +/*nRF24L01+ features, enable / disable as needed*/ +static uint8_t NRF24_en_ack = ENABLE; +static uint8_t NRF24_en_no_ack = ENABLE; +static uint8_t NRF24_en_dynamic_payload = ENABLE; /*global variables related to this file*/ static uint8_t SPI_command; /*1 byte spi command*/ @@ -13,7 +14,7 @@ static uint8_t current_address_width; /*current addr static uint8_t reset_flag = 0; /*reset flag lets the software know if the nrf24l01+ has ever been reset or not*/ static uint8_t current_mode = DEVICE_NOT_INITIALIZED; /*current mode of operation: DEVICE_NOT_INITIALIZED, PRX, PTX, STANDBYI, STANDBYII, POWER_DOWN*/ static uint8_t current_payload_width; /*payload width could be from 1 to 32 bytes, in either dynamic or static forms*/ -static uint8_t current_acknowledgement_state = NO_ACK_MODE; +static uint8_t current_acknowledgement_state = NO_ACK_MODE; /*2 dimensional array of pipe addresses (5 byte address width) by default. you can change addresses using a new array later. Pipe 1 address could be anything. pipe 3 to 6 addresses share the first 4 bytes with pipe 2 and only differ in byte 5*/ @@ -26,42 +27,6 @@ uint8_t datapipe_address[MAXIMUM_NUMBER_OF_DATAPIPES][ADDRESS_WIDTH_DEFAULT] = { {0X20, 0XC3, 0XC2, 0XC1, 0XA5} }; -/*function to enable or disable sending without acknowledge. - if disabled, you cannot disable acknowledging a payload. manipulates EN_DYN_ACK inside FEATURE*/ -void nrf24_payload_without_ack(uint8_t state) -{ - nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); - if (state == ENABLE) - { - register_new_value = register_current_value | (1 << EN_DYN_ACK); - } - else - { - register_new_value = register_current_value & (~(1 << EN_DYN_ACK)); - } - nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); -} - -void nrf24_payload_with_ack(uint8_t state) { - if (state == ENABLE) - { - nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); - register_new_value = register_current_value | (1 << EN_ACK_PAY) | (1 << EN_DPL); - nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); - nrf24_read(DYNPD_ADDRESS, ®ister_current_value, 1, CLOSE); - register_new_value = register_current_value | 0b111111; - nrf24_write(DYNPD_ADDRESS, ®ister_new_value, 1, CLOSE); - } - else - { - nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); - register_new_value = register_current_value & (~((1 << EN_ACK_PAY) | (1 << EN_DPL))); - nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); - } -} - - - /*function for PTX device to transmit 1 to 32 bytes of data, used for both dynamic payload length and static payload length methods. acknowledgemet state could be NO_ACK_MODE or ACK_MODE*/ uint8_t nrf24_transmit(uint8_t *payload, uint8_t payload_width, uint8_t acknowledgement_state) @@ -72,7 +37,7 @@ uint8_t nrf24_transmit(uint8_t *payload, uint8_t payload_width, uint8_t acknowle current_acknowledgement_state = acknowledgement_state; /*setting the acknowledgement state to either NO_ACK or ACK, based on input*/ if (NRF24_en_dynamic_payload == ENABLE) current_payload_width = payload_width; - nrf24_send_payload(payload, current_payload_width); /*the actual function to send data*/ + nrf24_send_payload(payload, payload_width); /*the actual function to send data*/ return (TRANSMIT_BEGIN); /*TX FIFO is not full and nrf24l01+ mode is standby ii or ptx*/ } else @@ -102,24 +67,6 @@ void nrf24_send_payload(uint8_t *payload, uint8_t payload_width) /*reports back transmit status: TRANSMIT_DONE, TRANSMIT_FAILED (in case of reaching maximum number of retransmits in auto acknowledgement mode) and TRANSMIT_IN_PROGRESS, if neither flags are set. automatically resets the '1' flags.*/ uint8_t nrf24_transmit_status() -{ - nrf24_read(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*status register is read to check TX_DS flag*/ - if (register_current_value & (1 << TX_DS)) /*if the TX_DS == 1, */ - { - nrf24_write(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*reseting the TX_DS flag. as mentioned by datasheet, writing '1' to a flag resets that flag*/ - return TRANSMIT_DONE; - } - else if (register_current_value & (1 << MAX_RT)) - { - nrf24_write(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*reseting the MAX_RT flag. as mentioned by datasheet, writing '1' to a flag resets that flag*/ - nrf24_flush(TX_BUFFER); - return TRANSMIT_FAILED; - } - else - return TRANSMIT_IN_PROGRESS; -} - -uint8_t nrf24_transmit_status_clear() { nrf24_read(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*status register is read to check TX_DS flag*/ if (register_current_value & (1 << TX_DS)) /*if the TX_DS == 1, */ @@ -213,7 +160,7 @@ uint8_t nrf24_flush(uint8_t fifo_select) /*must be called atleast once, which happens with calling nrf24_device function*/ void nrf24_reset() { - reset_flag = 1; + reset_flag = RESET; nrf24_CE(CE_OFF); register_new_value = CONFIG_REGISTER_DEFAULT; nrf24_write(CONFIG_ADDRESS, ®ister_new_value, 1, CLOSE); @@ -252,7 +199,7 @@ void nrf24_reset() nrf24_automatic_retransmit_setup(RETRANSMIT_DELAY_DEFAULT, RETRANSMIT_COUNT_DEFAULT); nrf24_auto_acknowledgment_setup(NUMBER_OF_DP_DEFAULT); nrf24_dynamic_payload(NRF24_en_dynamic_payload, NUMBER_OF_DP_DEFAULT); - nrf24_payload_without_ack(ENABLE); + nrf24_payload_without_ack(NRF24_en_no_ack); nrf24_payload_with_ack(NRF24_en_ack); } @@ -316,11 +263,8 @@ void nrf24_automatic_retransmit_setup(uint16_t delay_time, uint8_t retransmit_co /*setting auto acknoledgement on datapipes*/ void nrf24_auto_acknowledgment_setup(uint8_t datapipe) { - /* if (datapipe < 7) register_new_value = (1 << datapipe) - 1; - */ - register_new_value = EN_AA_REGISTER_DEFAULT; nrf24_write(EN_AA_ADDRESS, ®ister_new_value, 1, CLOSE); } @@ -336,11 +280,55 @@ void nrf24_dynamic_payload(uint8_t state, uint8_t datapipe) if (datapipe < 7) register_new_value = (1 << datapipe) - 1; /*turning on dynamic payload width on chosen datapipes, using DYNPD register*/ nrf24_write(DYNPD_ADDRESS, ®ister_new_value, 1, CLOSE); + NRF24_en_dynamic_payload = ENABLE; } else { register_new_value = register_current_value & (~(1 << EN_DPL)); nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + NRF24_en_dynamic_payload = DISABLE; + } +} + +/*function to enable or disable sending without acknowledge. + if disabled, TX must send a payload with ACK-request and receiver must be able to answer it. + manipulates EN_DYN_ACK inside FEATURE*/ +void nrf24_payload_without_ack(uint8_t state) +{ + if (state == ENABLE) + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value | (1 << EN_DYN_ACK); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + } + else + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value & (~(1 << EN_DYN_ACK)); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + } +} + +/*function to enable or disable sending with acknowledge. + if disabled, the payload can be sent only without ACK-request. + manipulates EN_ACK_PAY and EN_DPL inside FEATURE as Dynamic Payload Length is required.*/ +void nrf24_payload_with_ack(uint8_t state) +{ + if (state == ENABLE) + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value | (1 << EN_ACK_PAY) | (1 << EN_DPL); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + nrf24_read(DYNPD_ADDRESS, ®ister_current_value, 1, CLOSE); + // enable dynamic payload for all pipes + register_new_value = register_current_value | 0b111111; + nrf24_write(DYNPD_ADDRESS, ®ister_new_value, 1, CLOSE); + } + else + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value & (~((1 << EN_ACK_PAY) | (1 << EN_DPL))); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); } } @@ -447,6 +435,58 @@ void nrf24_rf_power(uint8_t rf_power) nrf24_write(RF_SETUP_ADDRESS, ®ister_new_value, 1, CLOSE); } +/*read whether the current channel is busy (has traffic), needs to be called from RX mode*/ +uint8_t nrf24_rf_channel_read_busy(uint8_t rf_channel) +{ + uint8_t signals_detected; + nrf24_read(RPD_REG_ADDRESS, &signals_detected, 1, CLOSE); + if (signals_detected) { + return CHANNEL_BUSY; + } + else { + return CHANNEL_CLEAR; + } +} + +/*test whether a channel is busy (has traffic), waiting for ms_to_test*/ +uint8_t nrf24_rf_channel_test_busy(uint8_t rf_channel, uint16_t ms_to_test) +{ + if ((rf_channel <= 125) && (rf_channel >= 1)) + { + // back up old channel + uint8_t previous_channel; + nrf24_read(RF_CH_ADDRESS, &previous_channel, 1, CLOSE); + // back up old mode + uint8_t previous_mode = current_mode; + // switch to new channel + nrf24_rf_channel(rf_channel); + // switch to RX, Received Power Detector is set to 0 and begins sampling + if (previous_mode != PRX) { + nrf24_mode(PRX); + } + // wait at least 1 ms before declaring channel clear + delay_function(1 > ms_to_test ? 1 : ms_to_test); + // Received Power Detector latches to 1 if there was a signal >-64dBm for at least 40 uS consecutively since RX mode was enabled + uint8_t signals_detected = nrf24_rf_channel_read_busy(rf_channel); + // switch back to old channel + nrf24_rf_channel(previous_channel); + // switch back to old mode + if (previous_mode != PRX) { + nrf24_mode(previous_mode); + } + if (signals_detected) { + return CHANNEL_BUSY; + } + else { + return CHANNEL_CLEAR; + } + } + else + { + return CHANNEL_BUSY; + } +} + /*nrf24l01+ RF channel selection, from 1 to 125*/ void nrf24_rf_channel(uint8_t rf_channel) { diff --git a/examples/spi_24L01_tx/NRF24L01_TX_Arduino/nrf24l01.h b/examples/spi_24L01_tx/NRF24L01_TX_Arduino/nrf24l01.h index 89d4b60f4a68fec76769922e59ef275f4d61679c..20876f691b44710ef4d034c78458623cbed827dc 100644 --- a/examples/spi_24L01_tx/NRF24L01_TX_Arduino/nrf24l01.h +++ b/examples/spi_24L01_tx/NRF24L01_TX_Arduino/nrf24l01.h @@ -4,10 +4,6 @@ #include <stdio.h> #include <stdint.h> - - - - #define STARTUP_DELAY 150 /*in milliseconds*/ #define POWER_DOWN_DELAY 2 #define STANDBYI_DELAY 2 @@ -66,6 +62,9 @@ #define RECEIVE_FIFO_EMPTY 2 #define TX_BUFFER 1 #define RX_BUFFER 0 +// return states for nrf24_rf_channel_test_busy +#define CHANNEL_CLEAR 0 +#define CHANNEL_BUSY 1 /*bits definition section*/ #define MASK_RX_DR 6 /*mask interrupt caused by RX_DR: 1 interrupt not reflected on IRQ pin (IRQ is active low), inside CONFIG register*/ @@ -116,7 +115,6 @@ #define RX_P_NO_2 3 #define RX_P_NO_1 2 #define RX_P_NO_0 1 -//#define TX_FULL 0 #define PLOS_CNT_3 7 /*inside OBSERVE_TX register, counts the total number of retransmissions since last channel change. reset by writing to RF_CH*/ #define PLOS_CNT_2 6 #define PLOS_CNT_1 5 @@ -191,6 +189,8 @@ void nrf24_mode(uint8_t mode); void nrf24_SPI(uint8_t input); void nrf24_CE(uint8_t input); void nrf24_address_width(uint8_t address_width); +uint8_t nrf24_rf_channel_read_busy(uint8_t rf_channel); +uint8_t nrf24_rf_channel_test_busy(uint8_t rf_channel, uint16_t ms_to_test); void nrf24_rf_channel(uint8_t rf_channel); void nrf24_rf_power(uint8_t rf_power); void nrf24_rf_datarate(uint16_t rf_datarate); @@ -205,6 +205,8 @@ void nrf24_datapipe_address_configuration(); void nrf24_datapipe_ptx(uint8_t datapipe_number); void nrf24_automatic_retransmit_setup(uint16_t delay_time, uint8_t retransmit_count); void nrf24_auto_acknowledgment_setup(uint8_t datapipe); +void nrf24_payload_without_ack(uint8_t state); +void nrf24_payload_with_ack(uint8_t state); void nrf24_dynamic_payload(uint8_t state, uint8_t datapipe); void nrf24_device(uint8_t device_mode, uint8_t reset_state); void nrf24_send_payload(uint8_t *payload, uint8_t payload_width); diff --git a/examples/spi_24L01_tx/SPI.h b/examples/spi_24L01_tx/SPI.h deleted file mode 100644 index 04898e2ee02cd69bc7fa8887799f78dd755d612b..0000000000000000000000000000000000000000 --- a/examples/spi_24L01_tx/SPI.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef SPI_H -#define SPI_H - -#include<stdint.h> //uintN_t support -#include"../../ch32v003fun/ch32v003fun.h" - -#define MIN(a,b) (((a)<(b))?(a):(b)) -#define MAX(a,b) (((a)>(b))?(a):(b)) - - -void SPI_poweron(); - -void kill_interrrupts(); -void restore_interrupts(); - -/* clock polarity and phase -CPOL leading trailing CPHA sample on -0 rising falling 0 leading -0 rising falling 1 trailing -1 falling rising 0 leading -1 falling rising 1 trailing -*/ -enum SPI_clk_modes{ - SPI_clk_mode_pol0_pha0_default, - SPI_clk_mode_pol0_pha1, - SPI_clk_mode_pol1_pha0, - SPI_clk_mode_pol1_pha1, -}; - -enum SPI_data_directions { - SPI_data_direction_2line_TxRx, // RX + TX 2-line bidirectional - SPI_data_direction_2line_Rx, // RX 2-line bidirectional - SPI_data_direction_1line_Rx, // RX 1-line unidirectional - SPI_data_direction_1line_Tx, // TX 1-line unidirectional -}; - -enum SPI_NSS_options { - SPI_NSS_hardware_PC0_default, // _NSS - SPI_NSS_hardware_PC1, // NSS but clashes with I2C SDA - SPI_NSS_software_PC3, - SPI_NSS_software_PC4, - SPI_NSS_software_any_manual, -}; - - -void SPI_NSS_software_high(); -void SPI_NSS_software_low(); - -void SPI_init( - uint32_t speedHz, - enum SPI_clk_modes clockMode, - enum SPI_data_directions dataDirection, - enum SPI_NSS_options NSSmode); -void SPI_begin_8(); -void SPI_begin_16(); -void SPI_end(); - - -void SPI_wait_TX_complete(); -uint8_t SPI_is_RX_empty(); -void SPI_wait_RX_available(); - - -void SPI_write_8(uint8_t data); -void SPI_write_16(uint16_t data); -uint8_t SPI_read_8(); -uint16_t SPI_read_16(); - - -uint8_t SPI_transfer_8(uint8_t data); -uint8_t SPI_transfer_16(uint16_t data); - - -void SPI_poweroff(); - - -#endif // SPI_H diff --git a/examples/spi_24L01_tx/SPI.c b/examples/spi_24L01_tx/ch32v003_SPI.h similarity index 63% rename from examples/spi_24L01_tx/SPI.c rename to examples/spi_24L01_tx/ch32v003_SPI.h index 90493b6217c8d1c81cc497f2a3a85e8514cdd063..786c230d29b0efc6ee0bf64703378ff3ba69cf46 100644 --- a/examples/spi_24L01_tx/SPI.c +++ b/examples/spi_24L01_tx/ch32v003_SPI.h @@ -1,69 +1,110 @@ -#include "SPI.h" +// you'll need to #define CH32V003_SPI_IMPLEMENTATION in the .c files that use this library. +// include guards +#ifndef CH32V003_SPI_H +#define CH32V003_SPI_H +// includes +#include<stdint.h> //uintN_t support +#include"../../ch32v003fun/ch32v003fun.h" -enum SPI_NSS_options NSS_selected; -uint16_t EXT1_INTENR_backup; +//######### SPI configuration states, use these for init() +// SPI peripheral config options +/* clock polarity and phase +CPOL leading trailing CPHA sample on +0 rising falling 0 leading +0 rising falling 1 trailing +1 falling rising 0 leading +1 falling rising 1 trailing +*/ +enum SPI_clk_modes{ + SPI_clk_mode_pol0_pha0_default, + SPI_clk_mode_pol0_pha1, + SPI_clk_mode_pol1_pha0, + SPI_clk_mode_pol1_pha1, +}; +enum SPI_data_directions { + SPI_data_direction_2line_TxRx, // RX + TX 2-line bidirectional + SPI_data_direction_2line_Rx, // RX 2-line bidirectional + SPI_data_direction_1line_Rx, // RX 1-line unidirectional + SPI_data_direction_1line_Tx, // TX 1-line unidirectional +}; +enum SPI_NSS_options { + SPI_NSS_hardware_PC0_default, // _NSS + SPI_NSS_hardware_PC1, // NSS but clashes with I2C SDA + SPI_NSS_software_PC3, + SPI_NSS_software_PC4, + SPI_NSS_software_any_manual, +}; + + + +//######### public function declarations, use these! +// initialize and configure the SPI peripheral +void SPI_init( + uint32_t speedHz, + enum SPI_clk_modes clockMode, + enum SPI_data_directions dataDirection, + enum SPI_NSS_options NSSmode); -void SPI_poweron() { - RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1; -} +// establish / end a connection to the SPI device +void SPI_begin_8(); +void SPI_begin_16(); +void SPI_end(); +// manually set the NSS pin high / low +void SPI_NSS_software_high(); +void SPI_NSS_software_low(); +// read / write the SPI device +// these commands are raw, you'll have to consider all other steps in SPI_transfer! +uint8_t SPI_read_8(); +uint16_t SPI_read_16(); +void SPI_write_8(uint8_t data); +void SPI_write_16(uint16_t data); -void kill_interrrupts() { - EXT1_INTENR_backup = EXTI->INTENR; - // zero the interrupt enable register to disable all interrupts - EXTI->INTENR = 0; -} +// send a command and get a response from the SPI device +// you'll use this for most devices +uint8_t SPI_transfer_8(uint8_t data); +uint8_t SPI_transfer_16(uint16_t data); -void restore_interrupts() { - EXTI->INTENR = EXT1_INTENR_backup; -} +// SPI peripheral power enable / disable (default off, init() automatically enables) +// send SPI peripheral to sleep +void SPI_poweroff(); +// wake SPI peripheral from sleep +void SPI_poweron(); +// helper: kill / restore all interrupts on the CH32V003 +void kill_interrrupts(); +void restore_interrupts(); -/* clock polarity and phase -CPOL leading trailing CPHA sample on -0 rising falling 0 leading -0 rising falling 1 trailing -1 falling rising 0 leading -1 falling rising 1 trailing -*/ -// software NSS output high -void SPI_NSS_software_high() { - switch (NSS_selected) { - case SPI_NSS_software_PC3: - GPIOC->BSHR |= (1<<3); - break; - case SPI_NSS_software_PC4: - GPIOC->BSHR |= (1<<4); - break; - default: - break; - } -} -// software NSS output low -void SPI_NSS_software_low() { - switch (NSS_selected) { - case SPI_NSS_software_PC3: - GPIOC->BSHR &= ~(1<<(16+3)); - break; - case SPI_NSS_software_PC4: - GPIOC->BSHR &= ~(1<<(16+4)); - break; - default: - break; - } -} +//############ h-file-only implementation section +// you'll need to #define CH32V003_SPI_IMPLEMENTATION in the .c files that use this library. +//#define CH32V003_SPI_IMPLEMENTATION //enable here so LSP can give you text colors while working on this library, disable for normal use of the library +#ifdef CH32V003_SPI_IMPLEMENTATION + + +//######### internal function declarations +static inline void SPI_wait_TX_complete(); +static inline uint8_t SPI_is_RX_empty(); +static inline void SPI_wait_RX_available(); +// min and max helper macros +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) +//######### internal variables +static enum SPI_NSS_options NSS_selected; +static uint16_t EXT1_INTENR_backup; + +//######### public function definitions void SPI_init( uint32_t speedHz, enum SPI_clk_modes clockMode, @@ -169,54 +210,53 @@ void SPI_begin_8() { SPI1->CTLR1 |= SPI_DataSize_8b; // DFF 16bit data-length enable, writable only when SPE is 0 SPI1->CTLR1 |= CTLR1_SPE_Set; } - void SPI_begin_16() { SPI1->CTLR1 |= SPI_DataSize_16b; // DFF 16bit data-length enable, writable only when SPE is 0 SPI1->CTLR1 |= CTLR1_SPE_Set; } - void SPI_end() { SPI1->CTLR1 &= CTLR1_SPE_Reset; } - - -void SPI_wait_TX_complete() { - while(!(SPI1->STATR & SPI_STATR_TXE)) { - asm volatile("nop"); +// software NSS output high +void SPI_NSS_software_high() { + switch (NSS_selected) { + case SPI_NSS_software_PC3: + GPIOC->BSHR |= (1<<3); + break; + case SPI_NSS_software_PC4: + GPIOC->BSHR |= (1<<4); + break; + default: + break; } } - -uint8_t SPI_is_RX_empty() { - return SPI1->STATR & SPI_STATR_RXNE; -} - -void SPI_wait_RX_available() { - while(!(SPI1->STATR & SPI_STATR_RXNE)) { - asm volatile("nop"); +// software NSS output low +void SPI_NSS_software_low() { + switch (NSS_selected) { + case SPI_NSS_software_PC3: + GPIOC->BSHR &= ~(1<<(16+3)); + break; + case SPI_NSS_software_PC4: + GPIOC->BSHR &= ~(1<<(16+4)); + break; + default: + break; } } - - -void SPI_write_8(uint8_t data) { - SPI1->DATAR = data; -} - -void SPI_write_16(uint16_t data) { - SPI1->DATAR = data; -} - uint8_t SPI_read_8() { return SPI1->DATAR; } - uint16_t SPI_read_16() { return SPI1->DATAR; } - - - +void SPI_write_8(uint8_t data) { + SPI1->DATAR = data; +} +void SPI_write_16(uint16_t data) { + SPI1->DATAR = data; +} uint8_t SPI_transfer_8(uint8_t data) { SPI_NSS_software_high(); SPI_write_8(data); @@ -226,7 +266,6 @@ uint8_t SPI_transfer_8(uint8_t data) { SPI_NSS_software_low(); return SPI_read_8(); } - uint8_t SPI_transfer_16(uint16_t data) { SPI_NSS_software_high(); SPI_write_16(data); @@ -237,10 +276,40 @@ uint8_t SPI_transfer_16(uint16_t data) { return SPI_read_16(); } - - void SPI_poweroff() { SPI_end(); RCC->APB2PCENR &= ~RCC_APB2Periph_SPI1; } +void SPI_poweron() { + RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1; +} + +void kill_interrrupts() { + EXT1_INTENR_backup = EXTI->INTENR; + // zero the interrupt enable register to disable all interrupts + EXTI->INTENR = 0; +} +void restore_interrupts() { + EXTI->INTENR = EXT1_INTENR_backup; +} + + + +//######### internal function definitions + +static void SPI_wait_TX_complete() { + while(!(SPI1->STATR & SPI_STATR_TXE)) { + asm volatile("nop"); + } +} +static uint8_t SPI_is_RX_empty() { + return SPI1->STATR & SPI_STATR_RXNE; +} +static void SPI_wait_RX_available() { + while(!(SPI1->STATR & SPI_STATR_RXNE)) { + asm volatile("nop"); + } +} +#endif // CH32V003_SPI_IMPLEMENTATION +#endif // CH32V003_SPI_H diff --git a/examples/spi_24L01_tx/nrf24l01.c b/examples/spi_24L01_tx/nrf24l01.c index fadd28d0e5a3055f77bdc1081ea370be27024ff3..9f3b0e34c9b3849e16b42e55a9cb245b32e55c83 100644 --- a/examples/spi_24L01_tx/nrf24l01.c +++ b/examples/spi_24L01_tx/nrf24l01.c @@ -1,8 +1,9 @@ #include "nrf24l01.h" -uint8_t NRF24_en_ack = ENABLE; -uint8_t NRF24_en_dynamic_payload = ENABLE; - +/*nRF24L01+ features, enable / disable as needed*/ +static uint8_t NRF24_en_ack = ENABLE; +static uint8_t NRF24_en_no_ack = ENABLE; +static uint8_t NRF24_en_dynamic_payload = ENABLE; /*global variables related to this file*/ static uint8_t SPI_command; /*1 byte spi command*/ @@ -13,7 +14,7 @@ static uint8_t current_address_width; /*current addr static uint8_t reset_flag = 0; /*reset flag lets the software know if the nrf24l01+ has ever been reset or not*/ static uint8_t current_mode = DEVICE_NOT_INITIALIZED; /*current mode of operation: DEVICE_NOT_INITIALIZED, PRX, PTX, STANDBYI, STANDBYII, POWER_DOWN*/ static uint8_t current_payload_width; /*payload width could be from 1 to 32 bytes, in either dynamic or static forms*/ -static uint8_t current_acknowledgement_state = NO_ACK_MODE; +static uint8_t current_acknowledgement_state = NO_ACK_MODE; /*2 dimensional array of pipe addresses (5 byte address width) by default. you can change addresses using a new array later. Pipe 1 address could be anything. pipe 3 to 6 addresses share the first 4 bytes with pipe 2 and only differ in byte 5*/ @@ -26,42 +27,6 @@ uint8_t datapipe_address[MAXIMUM_NUMBER_OF_DATAPIPES][ADDRESS_WIDTH_DEFAULT] = { {0X20, 0XC3, 0XC2, 0XC1, 0XA5} }; -/*function to enable or disable sending without acknowledge. - if disabled, you cannot disable acknowledging a payload. manipulates EN_DYN_ACK inside FEATURE*/ -void nrf24_payload_without_ack(uint8_t state) -{ - nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); - if (state == ENABLE) - { - register_new_value = register_current_value | (1 << EN_DYN_ACK); - } - else - { - register_new_value = register_current_value & (~(1 << EN_DYN_ACK)); - } - nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); -} - -void nrf24_payload_with_ack(uint8_t state) { - if (state == ENABLE) - { - nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); - register_new_value = register_current_value | (1 << EN_ACK_PAY) | (1 << EN_DPL); - nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); - nrf24_read(DYNPD_ADDRESS, ®ister_current_value, 1, CLOSE); - register_new_value = register_current_value | 0b111111; - nrf24_write(DYNPD_ADDRESS, ®ister_new_value, 1, CLOSE); - } - else - { - nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); - register_new_value = register_current_value & (~((1 << EN_ACK_PAY) | (1 << EN_DPL))); - nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); - } -} - - - /*function for PTX device to transmit 1 to 32 bytes of data, used for both dynamic payload length and static payload length methods. acknowledgemet state could be NO_ACK_MODE or ACK_MODE*/ uint8_t nrf24_transmit(uint8_t *payload, uint8_t payload_width, uint8_t acknowledgement_state) @@ -72,7 +37,7 @@ uint8_t nrf24_transmit(uint8_t *payload, uint8_t payload_width, uint8_t acknowle current_acknowledgement_state = acknowledgement_state; /*setting the acknowledgement state to either NO_ACK or ACK, based on input*/ if (NRF24_en_dynamic_payload == ENABLE) current_payload_width = payload_width; - nrf24_send_payload(payload, current_payload_width); /*the actual function to send data*/ + nrf24_send_payload(payload, payload_width); /*the actual function to send data*/ return (TRANSMIT_BEGIN); /*TX FIFO is not full and nrf24l01+ mode is standby ii or ptx*/ } else @@ -102,24 +67,6 @@ void nrf24_send_payload(uint8_t *payload, uint8_t payload_width) /*reports back transmit status: TRANSMIT_DONE, TRANSMIT_FAILED (in case of reaching maximum number of retransmits in auto acknowledgement mode) and TRANSMIT_IN_PROGRESS, if neither flags are set. automatically resets the '1' flags.*/ uint8_t nrf24_transmit_status() -{ - nrf24_read(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*status register is read to check TX_DS flag*/ - if (register_current_value & (1 << TX_DS)) /*if the TX_DS == 1, */ - { - nrf24_write(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*reseting the TX_DS flag. as mentioned by datasheet, writing '1' to a flag resets that flag*/ - return TRANSMIT_DONE; - } - else if (register_current_value & (1 << MAX_RT)) - { - nrf24_write(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*reseting the MAX_RT flag. as mentioned by datasheet, writing '1' to a flag resets that flag*/ - nrf24_flush(TX_BUFFER); - return TRANSMIT_FAILED; - } - else - return TRANSMIT_IN_PROGRESS; -} - -uint8_t nrf24_transmit_status_clear() { nrf24_read(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*status register is read to check TX_DS flag*/ if (register_current_value & (1 << TX_DS)) /*if the TX_DS == 1, */ @@ -213,7 +160,7 @@ uint8_t nrf24_flush(uint8_t fifo_select) /*must be called atleast once, which happens with calling nrf24_device function*/ void nrf24_reset() { - reset_flag = 1; + reset_flag = RESET; nrf24_CE(CE_OFF); register_new_value = CONFIG_REGISTER_DEFAULT; nrf24_write(CONFIG_ADDRESS, ®ister_new_value, 1, CLOSE); @@ -252,7 +199,7 @@ void nrf24_reset() nrf24_automatic_retransmit_setup(RETRANSMIT_DELAY_DEFAULT, RETRANSMIT_COUNT_DEFAULT); nrf24_auto_acknowledgment_setup(NUMBER_OF_DP_DEFAULT); nrf24_dynamic_payload(NRF24_en_dynamic_payload, NUMBER_OF_DP_DEFAULT); - nrf24_payload_without_ack(ENABLE); + nrf24_payload_without_ack(NRF24_en_no_ack); nrf24_payload_with_ack(NRF24_en_ack); } @@ -316,11 +263,8 @@ void nrf24_automatic_retransmit_setup(uint16_t delay_time, uint8_t retransmit_co /*setting auto acknoledgement on datapipes*/ void nrf24_auto_acknowledgment_setup(uint8_t datapipe) { - /* if (datapipe < 7) register_new_value = (1 << datapipe) - 1; - */ - register_new_value = EN_AA_REGISTER_DEFAULT; nrf24_write(EN_AA_ADDRESS, ®ister_new_value, 1, CLOSE); } @@ -336,11 +280,55 @@ void nrf24_dynamic_payload(uint8_t state, uint8_t datapipe) if (datapipe < 7) register_new_value = (1 << datapipe) - 1; /*turning on dynamic payload width on chosen datapipes, using DYNPD register*/ nrf24_write(DYNPD_ADDRESS, ®ister_new_value, 1, CLOSE); + NRF24_en_dynamic_payload = ENABLE; } else { register_new_value = register_current_value & (~(1 << EN_DPL)); nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + NRF24_en_dynamic_payload = DISABLE; + } +} + +/*function to enable or disable sending without acknowledge. + if disabled, TX must send a payload with ACK-request and receiver must be able to answer it. + manipulates EN_DYN_ACK inside FEATURE*/ +void nrf24_payload_without_ack(uint8_t state) +{ + if (state == ENABLE) + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value | (1 << EN_DYN_ACK); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + } + else + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value & (~(1 << EN_DYN_ACK)); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + } +} + +/*function to enable or disable sending with acknowledge. + if disabled, the payload can be sent only without ACK-request. + manipulates EN_ACK_PAY and EN_DPL inside FEATURE as Dynamic Payload Length is required.*/ +void nrf24_payload_with_ack(uint8_t state) +{ + if (state == ENABLE) + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value | (1 << EN_ACK_PAY) | (1 << EN_DPL); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); + nrf24_read(DYNPD_ADDRESS, ®ister_current_value, 1, CLOSE); + // enable dynamic payload for all pipes + register_new_value = register_current_value | 0b111111; + nrf24_write(DYNPD_ADDRESS, ®ister_new_value, 1, CLOSE); + } + else + { + nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE); + register_new_value = register_current_value & (~((1 << EN_ACK_PAY) | (1 << EN_DPL))); + nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE); } } @@ -447,6 +435,58 @@ void nrf24_rf_power(uint8_t rf_power) nrf24_write(RF_SETUP_ADDRESS, ®ister_new_value, 1, CLOSE); } +/*read whether the current channel is busy (has traffic), needs to be called from RX mode*/ +uint8_t nrf24_rf_channel_read_busy(uint8_t rf_channel) +{ + uint8_t signals_detected; + nrf24_read(RPD_REG_ADDRESS, &signals_detected, 1, CLOSE); + if (signals_detected) { + return CHANNEL_BUSY; + } + else { + return CHANNEL_CLEAR; + } +} + +/*test whether a channel is busy (has traffic), waiting for ms_to_test*/ +uint8_t nrf24_rf_channel_test_busy(uint8_t rf_channel, uint16_t ms_to_test) +{ + if ((rf_channel <= 125) && (rf_channel >= 1)) + { + // back up old channel + uint8_t previous_channel; + nrf24_read(RF_CH_ADDRESS, &previous_channel, 1, CLOSE); + // back up old mode + uint8_t previous_mode = current_mode; + // switch to new channel + nrf24_rf_channel(rf_channel); + // switch to RX, Received Power Detector is set to 0 and begins sampling + if (previous_mode != PRX) { + nrf24_mode(PRX); + } + // wait at least 1 ms before declaring channel clear + delay_function(1 > ms_to_test ? 1 : ms_to_test); + // Received Power Detector latches to 1 if there was a signal >-64dBm for at least 40 uS consecutively since RX mode was enabled + uint8_t signals_detected = nrf24_rf_channel_read_busy(rf_channel); + // switch back to old channel + nrf24_rf_channel(previous_channel); + // switch back to old mode + if (previous_mode != PRX) { + nrf24_mode(previous_mode); + } + if (signals_detected) { + return CHANNEL_BUSY; + } + else { + return CHANNEL_CLEAR; + } + } + else + { + return CHANNEL_BUSY; + } +} + /*nrf24l01+ RF channel selection, from 1 to 125*/ void nrf24_rf_channel(uint8_t rf_channel) { diff --git a/examples/spi_24L01_tx/nrf24l01.h b/examples/spi_24L01_tx/nrf24l01.h index 89d4b60f4a68fec76769922e59ef275f4d61679c..20876f691b44710ef4d034c78458623cbed827dc 100644 --- a/examples/spi_24L01_tx/nrf24l01.h +++ b/examples/spi_24L01_tx/nrf24l01.h @@ -4,10 +4,6 @@ #include <stdio.h> #include <stdint.h> - - - - #define STARTUP_DELAY 150 /*in milliseconds*/ #define POWER_DOWN_DELAY 2 #define STANDBYI_DELAY 2 @@ -66,6 +62,9 @@ #define RECEIVE_FIFO_EMPTY 2 #define TX_BUFFER 1 #define RX_BUFFER 0 +// return states for nrf24_rf_channel_test_busy +#define CHANNEL_CLEAR 0 +#define CHANNEL_BUSY 1 /*bits definition section*/ #define MASK_RX_DR 6 /*mask interrupt caused by RX_DR: 1 interrupt not reflected on IRQ pin (IRQ is active low), inside CONFIG register*/ @@ -116,7 +115,6 @@ #define RX_P_NO_2 3 #define RX_P_NO_1 2 #define RX_P_NO_0 1 -//#define TX_FULL 0 #define PLOS_CNT_3 7 /*inside OBSERVE_TX register, counts the total number of retransmissions since last channel change. reset by writing to RF_CH*/ #define PLOS_CNT_2 6 #define PLOS_CNT_1 5 @@ -191,6 +189,8 @@ void nrf24_mode(uint8_t mode); void nrf24_SPI(uint8_t input); void nrf24_CE(uint8_t input); void nrf24_address_width(uint8_t address_width); +uint8_t nrf24_rf_channel_read_busy(uint8_t rf_channel); +uint8_t nrf24_rf_channel_test_busy(uint8_t rf_channel, uint16_t ms_to_test); void nrf24_rf_channel(uint8_t rf_channel); void nrf24_rf_power(uint8_t rf_power); void nrf24_rf_datarate(uint16_t rf_datarate); @@ -205,6 +205,8 @@ void nrf24_datapipe_address_configuration(); void nrf24_datapipe_ptx(uint8_t datapipe_number); void nrf24_automatic_retransmit_setup(uint16_t delay_time, uint8_t retransmit_count); void nrf24_auto_acknowledgment_setup(uint8_t datapipe); +void nrf24_payload_without_ack(uint8_t state); +void nrf24_payload_with_ack(uint8_t state); void nrf24_dynamic_payload(uint8_t state, uint8_t datapipe); void nrf24_device(uint8_t device_mode, uint8_t reset_state); void nrf24_send_payload(uint8_t *payload, uint8_t payload_width); diff --git a/examples/spi_24L01_tx/nrf24l01_low_level.c b/examples/spi_24L01_tx/nrf24l01_low_level.c index 2578b0da9b3331c94a0eb2e1a029be94a5e360cf..da886d6de07b00cf64a3262f11045bee79ebe3c7 100644 --- a/examples/spi_24L01_tx/nrf24l01_low_level.c +++ b/examples/spi_24L01_tx/nrf24l01_low_level.c @@ -2,8 +2,8 @@ #define APB_CLOCK SYSTEM_CORE_CLOCK #include "../../ch32v003fun/ch32v003fun.h" -#include "SPI.h" - +#define CH32V003_SPI_IMPLEMENTATION +#include "ch32v003_SPI.h" #include "nrf24l01.h" /*start of low level functions, specific to the mcu and compiler*/ diff --git a/examples/spi_24L01_tx/spi_24L01_tx.c b/examples/spi_24L01_tx/spi_24L01_tx.c index e528558eea1bc2496ad47250d3da72bf3449d781..30588d5f3ebced43ef9556a92af5a7929b72325d 100644 --- a/examples/spi_24L01_tx/spi_24L01_tx.c +++ b/examples/spi_24L01_tx/spi_24L01_tx.c @@ -3,22 +3,22 @@ * 04-26-2023 recallmenot */ -// Could be defined here, or in the processor defines. #define SYSTEM_CORE_CLOCK 48000000 #define APB_CLOCK SYSTEM_CORE_CLOCK #include "../../ch32v003fun/ch32v003fun.h" -#include "SPI.h" #include <stdio.h> #include "nrf24l01.h" -#define TIME_GAP 1000 + +#define TIME_GAP 1000 uint8_t ascending_number = 0x00; char txt[16]; -// ####### start of main program ############################################################### + +//######### debug fn void uint8_to_binary_string(uint8_t value, char* output, int len) { for (int i = 0; i < len; i++) { @@ -50,6 +50,7 @@ void print_debug() { +//######### LED fn // led is PD4 to LED1 on board, which is (-) void led_on() { @@ -61,6 +62,9 @@ void led_off() { } + +//######### TX fn + uint8_t sendnumber() { return nrf24_transmit(&ascending_number, 1, ACK_MODE); } @@ -107,6 +111,9 @@ void send() { +//######### MAIN + + int main() { SystemInit48HSI(); @@ -114,11 +121,6 @@ int main() // start serial @ default 115200bps SetupUART( UART_BRR ); - // GPIO D4 Push-Pull for foreground blink - RCC->APB2PCENR |= RCC_APB2Periph_GPIOD; - GPIOD->CFGLR &= ~(0xf<<(4*4)); - GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4); - printf("\r\r\n\nspi_24L01_TX\n\r"); printf("initializing radio as TX..."); @@ -128,6 +130,13 @@ int main() print_debug(); + // GPIO D4 Push-Pull for foreground blink + RCC->APB2PCENR |= RCC_APB2Periph_GPIOD; + GPIOD->CFGLR &= ~(0xf<<(4*4)); + GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4); + + Delay_Ms(1000); + printf("looping...\n\r"); while(1) { diff --git a/minichlink/minichlink b/minichlink/minichlink new file mode 100755 index 0000000000000000000000000000000000000000..a92dfebdada0201b544bdc5af27e805a982cdd2e Binary files /dev/null and b/minichlink/minichlink differ diff --git a/minichlink/minichlink.so b/minichlink/minichlink.so new file mode 100755 index 0000000000000000000000000000000000000000..fe8f83436cbd1b3c09671ae6664a96cb12fb9cf8 Binary files /dev/null and b/minichlink/minichlink.so differ