📄 z1slaveio.c
字号:
/*= z1slaveio.c ================================================================
*
* Copyright (C) 2005 Nordic Semiconductor
*
* This file is distributed in the hope that it will be useful, but WITHOUT
* WARRANTY OF ANY KIND.
*
* Author(s): Borge Strand
*
* Description:
*
* Primitive access to internal registers in nRF24Z1.
* This file is independant of MCU, DAC and ADC.
*
* Compiler: Tested with WinAVR, avr-gcc (GCC) 3.4.3
*
* Revision: 2.0
*
*==============================================================================
*/
#include "z1slaveio.h"
// Read a single byte from nRF24Z1's slave interface using 2-wire
char z1_singleread(char adr) {
return mcu_2w_read(Z12WDEVADR, adr);
}
// Write a single byte to nRF24Z1's slave interface using 2-wire
void z1_singlewrite(char adr, char data) {
mcu_2w_write(Z12WDEVADR, adr, data);
}
// Wait until a flag indicates that registers are ready. Time out if it takes too long!
char z1_flagready(char flag) {
char inbyte;
int counter = MAXPOLLITER;
extern char error;
error = OKAY; // Nothing wrong found yet!
while (counter-- > 0) { // Only run permitted number of times
inbyte = z1_singleread(flag); // Read the flag through slave interface
if (inbyte==FLAGREADY) // Flag is ready,
return OKAY; // all is well
else if (inbyte==Z1TIMEOUT) // nRF24Z1 was unable to finish transfer but may receive new data
return OKAY; // Here if nRF24Z1 wasn't able to complete a transfer
else
mcu_wait_ms(POLLDURATION); // Wait before polling the flag again
}
return TIMEOUT; // Function timed out!
}
// Write 0x01 to a flag in order to initiate a transfer etc.
void z1_setflag(char flag) {
z1_singlewrite (flag, 0x01);
}
// Check four times in a row if nRF24Z1 has a link, this is a simple binary test!
char z1_haslink(void) {
char counter = 4;
while (counter-- != 0) {
if (z1_singleread(LNKSTA)!=LINKPRESENT) // Flag is not ready,
return 0; // Return signal of no link present
else // Flag is ready, but we should wait and check again
mcu_wait_ms(5);
}
return 1; // All link search attempts were successfull
}
// Wait for a link to be established, return z1_haslink(). Poll for a link LINKFINDCOUONTER times,
// each time waiting for LINKFINDPERIOD ms.
char z1_haslink_wait(void) {
char temp = LINKFINDCOUNTER;
while (temp != 0) { // Have we looked for a link for long enough?
#ifdef DEBUG
mcu_putchar('0'); // Monitor linkup
#endif
if (z1_haslink()) { // Did we find a link?
return 1; // If we did, quit happily
}
else { // If not, wait some more and look again
temp--;
mcu_wait_ms(LINKFINDPERIOD); // Give it chance to link up
}
}
return 0;
}
// Make ATX initiate a relink
void z1_force_relink(void) {
z1_singlewrite(LNKMOD, 0x10); // Write a "1" to LNKMOD[4] to force relink
}
// Turn ARX muting on and off
char z1_arx_mute(char muting) {
char temp = z1_flagready(RXCSTATE); // Check if ATX is ready to transfer new data to ARX
if (temp == OKAY) { // If it is, start processing mute data
if (muting == MUTEON) // Turning muting on, i.e. ARX goes quiet
z1_singlewrite(I2SCNF_OUT, z1_singleread(I2SCNF_OUT) | 0x40); // Set bit 6 of I2SCNF_OUT
else if (muting == MUTEOFF) // Turning muting off, i.e. ARX plays music
z1_singlewrite(I2SCNF_OUT, z1_singleread(I2SCNF_OUT) & ~0x40); // clear bit 6 of I2SCNF_OUT
z1_setflag(RXCSTATE); // Transfer new contents to ARX
}
return temp;
}
#ifdef Z1ALTERADDRESS
// The private address is used once the RX and TX link up. The RX is listening
// on this address if it comes back after having been out of range.
// This function assumes that the caller has tested flags before calling it. It will not
// perform any relinking, only set up the address and frequency hopping registers.
void z1_setprivateadr(void) {
z1_singlewrite(ADDR_0, mcu_randombyte()); // Data for ADDR_0 through ADDR_4
z1_singlewrite(ADDR_1, mcu_randombyte()); // Data for ADDR_0 through ADDR_4
z1_singlewrite(ADDR_2, mcu_randombyte()); // Data for ADDR_0 through ADDR_4
z1_singlewrite(ADDR_3, mcu_randombyte()); // Data for ADDR_0 through ADDR_4
z1_singlewrite(ADDR_4, mcu_randombyte()); // Data for ADDR_0 through ADDR_4
}
// The initial address is the one stored in an external EEPROM or MCU on the RX side.
// The RX will listen on this address after an RX power cycle.
// This function assumes that the caller has tested flags before calling it. It will not
// perform any relinking, only set up the address and frequency hopping registers.
void z1_setinitialadr(void) {
z1_singlewrite(ADDR_0, 0x98); // Data for ADDR_0
z1_singlewrite(ADDR_1, 0x38); // Data for ADDR_1
z1_singlewrite(ADDR_2, 0xA2); // Data for ADDR_2
z1_singlewrite(ADDR_3, 0x34); // Data for ADDR_3
z1_singlewrite(ADDR_4, 0x85); // Data for ADDR_4
}
#endif // Z1ALTERADDRESS
#ifdef USELED
// Turn a LED on the ARX on or off. The LED is located on DO1. It is active high.
// This feature only works with slave interface disabled in ARX.
void z1_arxled(char mode) {
char temp = z1_singleread(RXPIO);
if (z1_flagready(RXCSTATE) == OKAY) { // Okay to update ARX registers?
if (mode == LEDON)
temp |= 0x22; // Set DO1="1" with high drive high enable
else if (mode == LEDOFF)
temp &= 0xDD; // Set DO1="0" without high drive high enable
z1_singlewrite(RXPIO, temp); // Update RXPIO
z1_setflag(RXCSTATE); // Transfer contents to ARX
}
else {
#ifdef DEBUG
mcu_putchar('#'); // Indicate failure
#endif
}
}
// Rotate LED sequence and return LED code according to the MSB that is about to be rotated through left shift
char z1_rotate_led(void) {
extern unsigned int ledsequence; // FIX: hard code to 16-bit value
if (ledsequence & 0x8000) { // Check if the MSB of ledsequence is set
ledsequence <<= 1; // If it is, perform left-shift and
ledsequence |= 0x0001; // insert a "1" at the LSB end to make it circular
return LEDON; // Indicate that LED is to be turned on
}
else { // If MSB of ledsequence is cleared,
ledsequence <<= 1; // Perform left-shift which will insert a zero at the LSB end to make it circular
return LEDOFF; // Indicate that LED is to be turned off
}
}
#endif // USELED
#ifdef Z1INTERRUPT
// Report which interrupt is received. Interrupts are handled according to a priority list
char z1_intstatus(void) {
char temp = z1_singleread(INTSTA);
if ((temp & INT_LBROKEN) != 0x00)
return INT_LBROKEN;
else if ((temp & INT_LQUAL) != 0x00)
return INT_LQUAL;
else if ((temp & INT_RTRANS) != 0x00)
return INT_RTRANS;
else if ((temp & INT_RINPUT) != 0x00)
return INT_RINPUT;
else if ((temp & INT_LERROR) != 0x00)
return INT_LERROR;
else if ((temp & INT_WAKE) != 0x00)
return INT_WAKE;
else
return INT_VOID;
}
// Enable one or more interrupt sources in nRF24Z1, call it like this:
// z1_intinit(INT_LBROKEN | INT_LQUAL | INT_RINPUT); with the desired interrupt
// definitions OR'ed into one parameter byte. Interrupt output from ATX to MCU
// is active low in all of the program. It may be set active high by OR'ing interrupts by 0x80
void z1_intinit(char interrupts) {
z1_singlewrite(INTCF, interrupts); // Enable whatever interrupt was selected. This might trigger IRQ immediately
mcu_wait_ms(2); // Wait for possible interrupt to occur
if ((interrupts & INT_LQUAL) == 0x00) // If there is no interrupt due to poor link quality,
z1_singlewrite(LNKWTH, 0x00); // Don't give the corresponding flag a chance to occur
if ((interrupts & INT_LERROR) == 0x00) // If there is no interrupt due to link errors,
z1_singlewrite(LNKETH, 0xFF); // Don't give the corresponding flag a chance to occur
}
void z1_intdeactivate(void) {
z1_singlewrite(INTCF, 0x00); // Disable all nRF24Z1 interrupt sources
}
#endif // Z1INTERRUPT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -