📄 mcu_atmega16.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 + -