⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mcu_atmega16.c

📁 nordic 2.4G RF transceiver nRF24z01 firmware source code.
💻 C
字号:
/*= mcu_atmega16.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): B鴕ge Strand
 *
 * Description:
 *
 *   MCU specific code for Atmel atmega16
 *   This file must be ported to any other MCU to be used. 
 *   It implements all functions in mcu.h
 *   All defines specific to atmega16 reside in this file!
 *   All #includes specific to mcu family and compiler are in mcu.h
 *
 *   The following hardware is used in the ATmega16:
 *   PORTC[0:1] are used for 2-wire communication
 *   PORTB[...] are used for SPI communication
 *   PORTD[0:1] are used for UART communication
 *
 * Compiler: Tested with WinAVR, avr-gcc (GCC) 3.4.3
 *
 * Revision: 1.0 
 *
 *==============================================================================
 */


#include "mcu.h"


// MCU dependant local define
#define F_CPU 3686000UL 							// Clock frequency of MCU


// Some forward declarations of functions that are not available externally
void mcu_wait_timer(void);
int mcu_uart_putchar(char c);
int mcu_uart_getchar(void);
void mcu_spi_start(void);
char mcu_spi_byte(char);
void mcu_spi_end(void);


// Handler for timer/counter1 interrupt
SIGNAL(SIG_OVERFLOW1) { 
	// Simply return after interrupt
} 


// Initialize the MCU. The atmega16 needs no other init than what is done in
// separate functions. 
void mcu_init(void) {
	mcu_wait_ms(100);								// Wait for Z1 to load firmware and settings
}


// Halt the MCU for a number of 1ms periods.
void mcu_wait_ms(int time) {
	for (int i=1; i<=time; i++) {
		TCNT1 = -((uint16_t)(1e-3 * F_CPU));		// Sleep 1ms. Max is 65535 / 3686000 = 17ms
		mcu_wait_timer(); 							// Do the actual sleep
	}
}


// Go in to sleep mode after the calling function has set the desired delay
// The only allowable interrupt source is timer interrupt!
void mcu_wait_timer(void) { 
	TIMSK = (1<<TOIE1);							// Enable t/c 1 overflow int 
	TCCR1A = 0;										// t/c 1 normal mode 
	TCCR1B = (1<<CS10);							// Start timer 1 with prescaler 1 
	set_sleep_mode(SLEEP_MODE_IDLE);				// Idle mode keeps counters running
	sei(); 											// Set global interrupt flag
	sleep_mode();									// Wait until interrupted by pin or counter
	cli(); 											// Clear global interrupt flag
	TIMSK = 0x00;									// Disable all timer/counter interrupts
	TCCR1B = 0x00;									// Stop timer 1 
}  


#ifdef SLAVE_SPI

// Set up MCU's master SPI interface
void mcu_spi_master_init(void) {
	DDRB = 0xB0;									// SPI in(0)/out(1) SCK(7)=1, MISO(6)=0, MOSI(5)=1, CSN(4)=1
	PORTB = 0x10;									// CSN = 1 so that slave doesn't misunderstand
	SPCR = (1<<SPE)|(1<<MSTR);						// Enable SPI master at fck/4. Unscopeable on demo board
}


// Activate slave interface of Z1's SPI port
void mcu_spi_start(void) {
	PORTB = 0;										// CSN (and the rest of the port) is set low
	TCNT1 = -((uint16_t)(500e-6 * F_CPU));			// Sleep tdSSCK, 500祍
	mcu_wait_timer(); 								// Do the actual sleep
}


// Send and receive a single byte through the SPI interface
char mcu_spi_byte(char inbyte) {
	char outbyte;
	
	SPDR = inbyte;									// Start SPI transmit
	loop_until_bit_is_set(SPSR,SPIF);				// Wait until SPI transmit is done
	outbyte = SPDR;									// Load received SPI data
	TCNT1 = -((uint16_t)(500e-6 * F_CPU));			// Sleep tSRD, 500祍 after each SPI byte
	mcu_wait_timer(); 								// Do the actual sleep
	return outbyte;								// Return the byte just read
}


// De-activate slave interface of Z1's SPI port
void mcu_spi_end(void) {
	// spi_byte() has already waited tSRD. Assume that is enough before 
	// turning CSN off (=setting it to 1);
	PORTB = (1<<4);								// Setting bit 4 of PORTB
	TCNT1 = -((uint16_t)(500e-6 * F_CPU));			// Sleep tCMD, 500祍 between SPI transfers
	mcu_wait_timer(); 								// Do the actual sleep
}


// Run the shift registers through MCU master SPI port to Z1 slave SPI port
// DOC: Interrupts must be off during this function!
void mcu_spicycle(char startadr, char endadr) {
	extern char slaveinbuf[];						// Global data buffer from Z1 slave to MCU
	extern char slaveoutbuf[]; 					// Global data buffer from MCU to Z1 slave
	int n=0;						

	if (endadr - startadr < SLAVEBUFSIZE) {		// Assume that SPI interface can do autoinc access
		mcu_spi_start();							// Turn on active low chip select
		mcu_spi_byte(startadr);						// Send the start address with command bit
		while (startadr++ <= endadr) 			
			slaveinbuf[n] = mcu_spi_byte(slaveoutbuf[n++]);	// Shift register action
		mcu_spi_end();								// Turn off active low chip select
	}
}
#endif // SLAVE_SPI


#ifdef SLAVE_2W

#define Z12WDEVADR	0b00101001						// 7-bit Z1 slave device address with SADR (MSB) = 0 (on)
//#define Z12WDEVADR	0b01101001					// 7-bit Z1 slave device address with SADR (MSB) = 1 (off)

// Set up MCU's master SPI interface
void mcu_2w_master_init(void) {
	TWBR = 0x0C;									// SCL speed at a little below 100kb/s
	TWSR = 0;										// See mega16 datasheet, p178
	TWAR = 0xAA;									// 2-w adr. of this unit is 1010101, no answer to general call
	TWCR = (1<<TWEN);								// Enable two-wire interface
	TWDR = 0xFF;									// Default content = SDA released.
}


// Read data from 2-wire slave interface of Z1, this is all MCU specific!
// DOC: Interrupts must be off during this function!
void mcu_2wread(char startadr, char endadr) {
	extern char slaveinbuf[];						// Global data buffer from Z1 slave to MCU
	int n=0;

	// Brief explanation of Z1 2-wire read:
	// Send start condition
	// Send device address with r/_w = 0
	// Send internal register address
	// Send new start condition
	// Send device address with r/_w = 1
	// Read bytes, ACK if more bytes wanted, NACK when done
	// Send stop condition

	if (endadr - startadr < SLAVEBUFSIZE) {		// Check valid read length
		TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);	// Send start condition
		loop_until_bit_is_set(TWCR,TWINT);			// Wait until the start condition has been sent
		if ((TWSR & 0xF8) != 0x08)					// Test for valid start condition
			DB_PRINTF(PSTR ("S"));					// Report if it failed

		TWDR = (Z12WDEVADR<<1) & 0xFE;				// 7-bit device address, LSB=0 for write
		TWCR = (1<<TWINT) | (1<<TWEN);				// Start transmission of address
		loop_until_bit_is_set(TWCR,TWINT);			// Wait until the device address has been sent
		if ((TWSR & 0xF8) != 0x18)					// Test for ACK after device address and _w bit
			DB_PRINTF(PSTR ("1"));					// Report if it failed

		TWDR = startadr;							// Send internal address of Z1
		TWCR = (1<<TWINT) | (1<<TWEN);				// Start transmission of address
		loop_until_bit_is_set(TWCR,TWINT);			// Wait until the internal address has been sent
		if ((TWSR & 0xF8) != 0x28)					// Test for ACK after data = internal address
			DB_PRINTF(PSTR ("2"));					// Report if it failed

		TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);	// Send another start condition
		loop_until_bit_is_set(TWCR,TWINT);			// Wait until the start condition has been sent
		if ((TWSR & 0xF8) != 0x10)					// Test for valid restart condition sent
			DB_PRINTF(PSTR ("Rs"));					// Report if it failed

		TWDR = (Z12WDEVADR<<1) | 0x01;				// 7-bit device address, LSB=1 for read
		TWCR = (1<<TWINT) | (1<<TWEN);				// Start transmission of address
		loop_until_bit_is_set(TWCR,TWINT);			// Wait until the device address has been sent
		if ((TWSR & 0xF8) != 0x40)					// Test for ACK after device address and r bit
			DB_PRINTF(PSTR ("3"));					// Report if it failed
	
		while (startadr <= endadr) {				// Read bytes until done
			if (startadr++ == endadr) {			// Must send NACK after last receive
				TWCR = (1<<TWINT) | (1<<TWEN);		// Initiate reception
				loop_until_bit_is_set(TWCR,TWINT);	// Wait until data has been received
				if ((TWSR & 0xF8) != 0x58)			// Check reception of last byte
					DB_PRINTF(PSTR ("d"));			// Report if it failed
			}
			else {
				TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);	// Send ACK after intermediate receive
				loop_until_bit_is_set(TWCR,TWINT);	// Wait until data has been received
				if ((TWSR & 0xF8) != 0x50)			// Check reception of intermediate byte
					DB_PRINTF(PSTR ("D"));			// Report if it failed
			}
			slaveinbuf[n++] = TWDR;				// Read the actual data
		} // while more data to read
		TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);	// Send stop condition
	} // if valid read length
} // mcu_2wread


// Write data to 2-wire slave interface of Z1, this is all MCU specific!
// DOC: Interrupts must be off during this function!
void mcu_2wwrite(char startadr, char endadr) {
	extern char slaveoutbuf[];						// Global data buffer from MCU to Z1 slave
	int n=0;

	// Brief explanation of Z1 2-wire write:
	// Send start condition
	// Send device address with r/_w = 0
	// Send internal register address
	// Send bytes
	// Send stop condition

	if (endadr - startadr < SLAVEBUFSIZE) {		// Check valid read length
		TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);	// Send start condition
		loop_until_bit_is_set(TWCR,TWINT);			// Wait until the start condition has been sent
		if ((TWSR & 0xF8) != 0x08)					// Test for valid start condition
			DB_PRINTF(PSTR ("S"));					// Report if it failed
			
		TWDR = (Z12WDEVADR<<1) & 0xFE;				// 7-bit device address, LSB=0 for write
		TWCR = (1<<TWINT) | (1<<TWEN);				// Start transmission of address
		loop_until_bit_is_set(TWCR,TWINT);			// Wait until the device address has been sent
		if ((TWSR & 0xF8) != 0x18)					// Test for ACK after device address and _w bit
			DB_PRINTF(PSTR ("1"));					// Report if it failed

		TWDR = startadr;							// Send internal address of Z1
		TWCR = (1<<TWINT) | (1<<TWEN);				// Start transmission of address
		loop_until_bit_is_set(TWCR,TWINT);			// Wait until the internal address has been sent
		if ((TWSR & 0xF8) != 0x28)					// Test for ACK after data = internal address
			DB_PRINTF(PSTR ("2"));					// Report if it failed
	
		while (startadr++ <= endadr) {				// Write bytes until done, compare address data, not buffer index
			TWDR = slaveoutbuf[n++];				// Write the actual data
			TWCR = (1<<TWINT) | (1<<TWEN);			// Initiate reception
			loop_until_bit_is_set(TWCR,TWINT);		// Wait until data has been received
			if ((TWSR & 0xF8) != 0x28)				// Test for ACK after data transfer
				DB_PRINTF(PSTR ("D"));				// Report if it failed
		} // while more data to write
		
		TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);	// Send stop condition
	} // if valid write length
} // mcu_2wwrite
#endif // SLAVE_2W


// Sends a single char over the uart
int mcu_uart_putchar(char c) {
	loop_until_bit_is_set(UCSRA,UDRE);				// Wait until the send register is empty, atmega16
	UDR = c;										// Send char to send register
	return 0;
}


// Halts, then receives a single char from the uart. Immediate echo
int mcu_uart_getchar(void) {
	char c;
	loop_until_bit_is_set(UCSRA,RXC);				// Wait untill a char is received, atmega16
	c = UDR;										// Read char from uart
	mcu_uart_putchar (c);							// Echo the character	
	return c;
}


// Sets up the uart for 57600 baud, 8 data, 1 stop with a 3.686MHz clock
void mcu_uart_init(void) {
	UBRRH = 0x00;									// Set up for 57600 baud at 3.686MHz clock
	UBRRL = 0x03;
	UCSRB = (1<<RXEN)|(1<<TXEN);					// Enable both read and write
	UCSRC = (1<<URSEL)|(3<<UCSZ0);					// 8 bits data, 1 stop bit

	fdevopen(mcu_uart_putchar, mcu_uart_getchar, 0);	// Enable C functions for i/o
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -