📄 i2c_bf561_rev04.asm
字号:
/*****************************************************************************
* I2C_BF561_rev04.asm
*
* Copyright (c) 2007 Analog Devices, Inc. All Rights Reserved.
* This software is proprietary to Analog Devices, Inc. and its
* licensors.
*
* CHANGES: 10/24/2007 1.00 - initial public release
*
* SOFTWARE: VisualDSP++ 5.0 August 2007 Update
*
* HARDWARE: BF561 EZ-Kit Lite Board Rev 1.4
* Micron MTV9022 or MTV9032 Sensor
*
*
* DESCRIPTION:
*
* SCCB Software Interface for Video Device configurations - C Callable
*
* This header implements the I2C read and write functions.
*
*
* SCCB START SETTINGS:
*
* >> Before Calling the SCCB_Interface
* the inputs to the SCCB_Taskmanager must be done.
*
* >> Write to the "SCCB_Control"
* a "1" for reading from the Device or
* a "2" for writing to the Device.
*
* >> Leave the total number of bytes in "SCCB_Wordcount".
* Device Addresses and Word Addresses included.
*
* >> Write all data to the "SCCB_DataIn"
* e.g.Writing to the device:
*
* SCCB_DataIn Device Address (LSB must be Zero)
* Word Address
* Data 1
* Data 2
* e.g.Reading from the device:
*
* SCCB_DataIn Device Address (LSB must be zero)
* Word Address
* Device Address (LSB must be one)
* >> The data elements received can be found in the array
* _SCCB_DataOut[10]
* HISTORY:
* 04 October 06: Taken from TL's rev 3.0
* - added Error Handling.
* - modified labels to make this function C-callable
* (not using macros)
* - added TWI_primitives.c to this package to call
* it for any combination of 8/16 register/data
* size read/writes
*
*
* NOTE: hard coded to use EVT10 and SICA_IMASK1 (bit 3)!
*
*******************************************************************************/
#include <defBF561.h>
/*************** SCCB Constants ************************************/
#define ISR_SCCB_Timer 0xFFE02028 // Address of the interrupt register (EVT10 in this case)
#define System_MMR_High_Address 0xFFC00000 // The high address word is handled like pages
#define Core_MMR_High_Address 0xFFE00000 // The high address word is handled like pages
#define SCL_PERIOD 0x80 // scl_period ~= 320kHz at 120MHz SYSCLK
//#define SCL_PERIOD 0x200 // scl_period >= 133MHz/(3 x 0.4MHz)
#define SCL_HIGH SCL_PERIOD >> 1
#define SCL 0x1 // serial clock is PF1
#define SDA 0x2 // serial data is PF0
#define scl_bit 0 // scl = PF1
#define sda_bit 1 // sda = PF0
#define MAX_TRANSACTIONS (256*2)+ 10 // max bytes
/*************** SCCB Variables ************************************/
.section L1_data_a;
.var SCCB_Variable_High_Address;
.var _SCCB_Control;
.var SCCB_Bit_Count;
.var _SCCB_Word_Count ;
.var SCCB_Write_Read_Register;
.var SCCB_Data_Pointer;
.var _SCCB_DataIn[MAX_TRANSACTIONS];
.var _SCCB_DataOut[MAX_TRANSACTIONS];
.var SCCB_Point_of_State;
.var SCCB_Read_Count;
.var _SCCB_In_Progress = 0;
.var SCCB_Read_Start_Cond0_Task_Val;
.var _SCCB_Error = 0;
/*************** SCCB Macros ****************************************/
//These macros are used in all routine to push/pop all registers
//and to reset the timer interrupt again
#define SCCB_Start_Macro\
[--SP] = ASTAT;\
[--SP] = FP;\
[-- SP] = (R7:0, P5:0);\
SP+= -64;\
SP+= -56;\
link 0x0;\
[FP+0x8] = R0;\
[FP+0xC] = R1;\
[FP + 0x10] = R2
#define SCCB_End_Macro\
p0.h = hi(TMRS8_STATUS);\
p0.l = lo(TMRS8_STATUS);\
R0 = 0x0011 (z);\
w[p0] = R0;\
JUMP.S 2;\
unlink;\
SP+=60;\
SP+=60;\
(R7:0, P5:0) = [SP++];\
FP = [SP++];\
ASTAT = [SP++];\
SSYNC
/**********************************************************************/
/*************** SCCB Global Settings *********************************/
.section L1_code;
.global _SCCB_Interface;
.global _SCCB_Control;
.global _SCCB_Word_Count;
.global _SCCB_DataIn;
.global _SCCB_DataOut;
.global SCCB_Read_Count;
.global _SCCB_In_Progress;
.global _SCCB_Error;
/**********************************************************************/
/*************** SCCB Main Init ***************************************/
///////////////////////////////////////////////////////////////////////////
//No register must be kept for this Interface because all contents are //
//stored in the variables above. As you can see before entering the //
//_SCCB_Interface Subroutine all registers will be pushed onto the stack. //
//For each access to the SCCB device this subroutine will just be executed/
//one time. After execution the pushed registers are poped back again. //
//The Timer interrupt initialized in this "asm" file will link to the //
//subroutines required for this interface each time it comes up //
//The data sent to the device will be eight bits wide for configuration //
//purposes to video devices only. //
///////////////////////////////////////////////////////////////////////////
_SCCB_Interface:
SCCB_Start_Macro;
/*************** SCCB Timer Interrupt Vector Init ***********************/
//In case the timer will be used for several applications the Interrupt
//vetctor for this Interface is set here. The address of the routine to be
//executed at first is filled in the interrupt register here.
P0.H = hi(ISR_SCCB_Timer);
P0.L = lo(ISR_SCCB_Timer); //Base address of the interrupt vector
r0.h = SCCB_Start_Cond1;
r0.l = SCCB_Start_Cond1;
[p0] = R0; //ISR Start Address will be written in the EVT register
/*************** SCCB GPIO init as SDA and SCL ****************************/
p0.h = hi(System_MMR_High_Address); //High address of all the system registers
// disable PF inputs
p0.l = lo(FIO0_INEN);
r0 = w[p0](z);
bitclr(r0, scl_bit);
bitclr(r0, sda_bit);
w[p0] = r0;
//Set bit PF1(SDA) & PF0(SCL) as outputs
p0.l = lo(FIO0_DIR);
r0 = w[p0](z);
bitset(r0, scl_bit);
bitset(r0, sda_bit);
w[p0] = r0;
//The Flag PF1(SDA) and PF0(SCL) shall be high
p0.l = lo(FIO0_FLAG_S);
r0 = SCL (z);
bitset(r0, sda_bit);
bitset(r0, scl_bit);
w[p0] = r0;
/*************************************************************************/
/***************** SCCB Timer0 Init ***************************************/
p0.h = hi(System_MMR_High_Address); //High address of all the system registers
p0.l = lo(TMRS8_STATUS);
r0.l = 0x0011; w[p0] = r0; //Clear Timer Interrupt and Overflow bit
p0.l = lo(TMRS8_DISABLE); //disable timer
r1 = 0x0001(z);
w[p0] = r1;
/* Setup Timer0: PWM_OUT mode, pulse hi, count to end of */
/* period, interrupt, sample TMR0 pin, disable pad, EMU_RUN enable */
/* Bit configuration: 0x025D = 0010 0010 0101 1101 */
P0.L = TIMER0_CONFIG & 0xffff;
P0.H = TIMER0_CONFIG >> 16;
R0.L = 0x025D;
W[P0] = R0.L;
// The period is set to provide a 3:1 ratio of SCL to TMR0
P0.L = TIMER0_PERIOD & 0xffff;
P0.H = TIMER0_PERIOD >> 16;
R0 = SCL_PERIOD (z);
[P0] = R0;
// Width of provides 50% duty cycle: scl_high = 1/2 of scl_period
P0.L = TIMER0_WIDTH & 0xffff;
P0.H = TIMER0_WIDTH >> 16;
R0 = SCL_PERIOD >> 1 (z);
[P0] = R0;
/*************************************************************************/
/*************** SCCB Timer0 Interrupt ************************************/
p0.h = hi(System_MMR_High_Address); //High address of all the system registers
p0.l = lo(SICA_IMASK1); //Timer0 has been enabled
r0 = [p0];
bitset(r0,3);
[p0] = r0;
p0.h = hi(IMASK);
p0.l = lo(IMASK);
r0 = [p0];
bitset(r0,10);
[p0] = r0; //Enable the "IVEC10" interrupt
p0.h = hi(System_MMR_High_Address); //High address of all the system registers
p0.l = lo(TMRS8_ENABLE); //enable timer
r1 = 0x0001(z);
w[p0] = r1;
/*************************************************************************/
/*************** SCCB Start Setup ****************************************/
/* */
/*************************************************************************/
//prepares the variables used in this Interface
p1.h = SCCB_Variable_High_Address; //works as a page for all Variables
p2.h = SCCB_Variable_High_Address;
p1.l = SCCB_Bit_Count;
r0 = 0x8;
[p1] = r0;
p1.l = SCCB_Read_Count;
r0 = 0x2; // dev wr addr + word addr to start
[p1] = r0;
p1.l = SCCB_Read_Start_Cond0_Task_Val;
r0 = 0; // due to an extra start condition at reading from device
[p1] = r0; // this variable is reqired
p1.l = _SCCB_DataIn;
p2.l = SCCB_Data_Pointer;
[p2] = p1;
p2.l = SCCB_Write_Read_Register;
r0 = [p1];
[p2] = r0;
/*************************************************************************/
SCCB_End_Macro;
_SCCB_Interface.END:
RTS;
//This is the end of the Init program. All other subroutine will be called
//by the Timer Interrupt separately.
/*************** SCCB End of Init ****************************************/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
//Each timer interrupt will just call one of the following subroutines.
//That restults to a SCCB speed depending of the Timer speed. The time
//between the timer interrupts can be used for processing of user data
//there are no loops that would cause a decrease of processor speed
/*************** SCCB Start Cond1 ****************************************/
SCCB_Start_Cond1:
SCCB_Start_Macro;
p0.h = hi(System_MMR_High_Address); //High address of all the system registers
p0.l = lo(FIO0_FLAG_C); //The Flag PF0 (SDA) will be cleared at first (Start Condition!)
r0.l = SDA;
w[p0] = r0;
P0.H = hi(ISR_SCCB_Timer); P0.L = lo(ISR_SCCB_Timer); //Base address of the interrupt vector
r0.h = SCCB_Start_Cond2; r0.l = SCCB_Start_Cond2;
[p0] = R0; //ISR Start Address will be written in the EVT register
SCCB_End_Macro;
RTI;
/*************** SCCB Start Cond2 ****************************************/
SCCB_Start_Cond2:
SCCB_Start_Macro;
p0.h = hi(System_MMR_High_Address); //High address of all the system registers
p0.l = lo(FIO0_FLAG_C); //The Flag PF1 (SCL) will be cleared at second (Start Condition!)
r0.l = SCL;
w[p0] = r0;
P0.H = hi(ISR_SCCB_Timer); P0.L = lo(ISR_SCCB_Timer); //Base address of the interrupt vector
r0.h = SCCB_Send_Data; r0.l = SCCB_Send_Data;
[p0] = R0; //ISR Start Address will be written in the EVT register
SCCB_End_Macro;
RTI;
/*************** SCCB Send Data to the Device*******************************/
//"SCCB_Send_Data" will send all the addresses and data required for communication
//to the device. The data must be shifted through the GPIO Pin 0
SCCB_Send_Data:
SCCB_Start_Macro;
p0.h = hi(System_MMR_High_Address); //High address of all the system registers
p1.h = SCCB_Variable_High_Address; //works as a page for all Variables
p1.l = SCCB_Write_Read_Register;
r0 = [p1];
p1.l = SCCB_Bit_Count; //load the bit counter to count the
r1 = [p1];
CC = r1 == 0;
IF CC JUMP SCCB_Send_DATA_Word_Sent;//If eight bits are sent get the next byte
CC = BITTST(r0, 7);
IF CC JUMP SCCB_Send_DATA_SET_SDA; //Check the data bit in order to clear or
p0.l = lo(FIO0_FLAG_C); //The contents of the bit check was zero
r5.l = SDA;
w[p0] = r5; //so the GPIO pin must been cleared
JUMP SCCB_Bit_Sent_End;
SCCB_Send_DATA_SET_SDA:
p0.l = lo(FIO0_FLAG_S); //So, the GPIO pin must been set
r5.l = SDA;
w[p0] = r5;
SCCB_Bit_Sent_End:
r0 = r0 << 1; //shift the byte to get the next bit
p1.l = SCCB_Write_Read_Register; //save the shifted byte for the run
[p1] = r0;
p1.l = SCCB_Bit_Count;
r1 += -1; //decrement the bit counter.
[p1] = r1; //So, that last bit can be detected
P0.H = hi(ISR_SCCB_Timer); P0.L = lo(ISR_SCCB_Timer); //Base address of the interrupt vector
r0.h = SCCB_Write_Clock; r0.l = SCCB_Write_Clock;
[p0] = R0; //ISR Start Address will be written in the EVT register
SCCB_End_Macro;
RTI;
SCCB_Send_DATA_Word_Sent: //byte has been sent
p0.l = lo(FIO0_DIR);
r0.l = w[p0];
bitclr(r0, sda_bit); //configure SDA bit as an Input
w[p0] = r0;
// enable PF inputs
p0.l = lo(FIO0_INEN);
r0 = w[p0](z);
bitset(r0, sda_bit);
w[p0] = r0;
P0.H = hi(ISR_SCCB_Timer); P0.L = lo(ISR_SCCB_Timer); //Base address of the interrupt vector
r0.h = SCCB_ACK_TST; r0.l = SCCB_ACK_TST;
[p0] = R0; //ISR Start Address will be written in the EVT register
SCCB_End_Macro;
RTI;
/*************** SCCB Send Data to the Device finish *******************************/
/*************** SCCB SCCB Clock routine********************************************/
SCCB_Write_Clock:
SCCB_Start_Macro;
p0.h = hi(System_MMR_High_Address); //High address of all the system registers
p1.h = SCCB_Variable_High_Address; //works as a page for all Variables
p0.l = lo(FIO0_FLAG_S);
r0.l = W[p0];
CC = BITTST (r0, scl_bit);
IF CC JUMP SCCB_Set_Write_Clock_Low; // if scl high, then set it low
r0 = SCL(z); // if scl low, then set it high
w[p0] = r0;
SCCB_End_Macro;
RTI; // remain in this state upon the next interrupt
SCCB_Set_Write_Clock_Low:
p0.l = lo(FIO0_FLAG_C);
r0 = SCL(z);
w[p0] = r0;
p1.l = SCCB_Bit_Count; //load the bit counter to count the
r1 = [p1];
CC = r1 == 0;
IF !CC JUMP JUST_TOGGLE_LOW;//If eight bits are sent, stop driving SDA
p0.l = lo(FIO0_DIR);
r0.l = w[p0];
bitclr(r0, sda_bit); //configure SDA bit as an Input
w[p0] = r0;
// enable PF inputs
p0.l = lo(FIO0_INEN);
r0 = w[p0](z);
bitset(r0, sda_bit);
w[p0] = r0;
JUST_TOGGLE_LOW:
P0.H = hi(ISR_SCCB_Timer); P0.L = lo(ISR_SCCB_Timer); //Base address of the interrupt vector
r0.h = SCCB_Send_Data; r0.l = SCCB_Send_Data;
[p0] = R0; //ISR Start Address will be written in the EVT register
SCCB_End_Macro;
RTI;
/**************************************************************/
/*************** SCCB SCCB Acknowledge routines****************/
SCCB_ACK_Wait: // After receiving a word an extra delay is insterted
SCCB_Start_Macro;
p0.h = hi(System_MMR_High_Address); //High address of all the system registers
p1.h = SCCB_Variable_High_Address; //works as a page for all Variables
p1.l = _SCCB_Word_Count;
r1 = [p1];
CC = r1 == 1;
IF CC JUMP No_Acknowledge_By_Master;
P0.H = hi(ISR_SCCB_Timer);
P0.L = lo(ISR_SCCB_Timer); // Int Vector Base Addr
r0.h = SCCB_ACK_TST;
r0.l = SCCB_ACK_TST; // next state: test for ACK
[p0] = R0;
SCCB_End_Macro;
RTI;
No_Acknowledge_By_Master:
p0.l = lo(FIO0_FLAG_S); // drive SCL high
r0 = SCL(z);
w[p0] = r0;
P0.H = hi(ISR_SCCB_Timer);
P0.L = lo(ISR_SCCB_Timer); // Int Vector Base Addr
r0.h = SCCB_ACK_MNGR;
r0.l = SCCB_ACK_MNGR; // next state: test for ACK
[p0] = R0;
SCCB_End_Macro;
RTI;
SCCB_ACK_TST:
SCCB_Start_Macro;
p0.h = hi(System_MMR_High_Address); //High address of all the system registers
p0.l = lo(FIO0_FLAG_S); // drive SCL high
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -