mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-19 21:11:57 -04:00
Update the SmartFusion SoftConsole source code to be the same as the IAR and Keil versions.
This commit is contained in:
parent
2aef3e3cfe
commit
eadd0048c4
|
@ -318,7 +318,7 @@ void OLED_init(void )
|
|||
*/
|
||||
void OLED_clear_display( oled_no_of_line LINES )
|
||||
{
|
||||
uint8_t i, j,start_line,end_line;
|
||||
uint8_t i, j,start_line = 0,end_line = 0;
|
||||
uint8_t clear_8_columns[] =
|
||||
{
|
||||
OLED_DATA_CODE, 0x00,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,306 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SVN $Revision: 2905 $
|
||||
* SVN $Date: 2010-08-20 14:03:28 +0100 (Fri, 20 Aug 2010) $
|
||||
*/
|
||||
#include "mss_ace.h"
|
||||
#include "mss_ace_configurator.h"
|
||||
#include "../../drivers_config/mss_ace/ace_handles.h"
|
||||
#include "../../drivers_config/mss_ace/ace_config.h"
|
||||
|
||||
#include "../../CMSIS/a2fxxxm3.h"
|
||||
#include "../../CMSIS/mss_assert.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SSE_START 1uL
|
||||
#define SSE_STOP 0uL
|
||||
|
||||
#define NB_OF_ANALOG_BLOCKS 3u
|
||||
#define SEE_RAM_WORD_SIZE 512
|
||||
|
||||
#define TS_ENABLE_MASK 0x01u
|
||||
#define PPE_ENABLE_MASK 0x01u
|
||||
#define ADC_RESET_MASK 0x10u
|
||||
#define ADC_FIFO_CLR_MASK 0x04u
|
||||
#define PDMA_DATAOUT_CLR_MASK 0x04u
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
extern ace_procedure_desc_t g_sse_sequences_desc_table[ACE_NB_OF_SSE_PROCEDURES];
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
sse_sequence_handle_t
|
||||
ACE_get_sse_seq_handle
|
||||
(
|
||||
const uint8_t * p_sz_sequence_name
|
||||
)
|
||||
{
|
||||
uint16_t seq_idx;
|
||||
sse_sequence_handle_t handle = INVALID_SSE_SEQ_HANDLE;
|
||||
|
||||
for ( seq_idx = 0u; seq_idx < (uint32_t)ACE_NB_OF_SSE_PROCEDURES; ++seq_idx )
|
||||
{
|
||||
if ( g_sse_sequences_desc_table[seq_idx].p_sz_proc_name != 0 )
|
||||
{
|
||||
int32_t diff;
|
||||
diff = strncmp( (const char *)p_sz_sequence_name, (const char *)g_sse_sequences_desc_table[seq_idx].p_sz_proc_name, MAX_PROCEDURE_NAME_LENGTH );
|
||||
if ( 0 == diff )
|
||||
{
|
||||
/* channel name found. */
|
||||
handle = seq_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
static uint32_t volatile * const sse_pc_ctrl_lut[NB_OF_ANALOG_BLOCKS] =
|
||||
{
|
||||
&ACE->PC0_CTRL,
|
||||
&ACE->PC1_CTRL,
|
||||
&ACE->PC2_CTRL
|
||||
};
|
||||
|
||||
static uint32_t volatile * const sse_pc_lo_lut[NB_OF_ANALOG_BLOCKS] =
|
||||
{
|
||||
&ACE->PC0_LO,
|
||||
&ACE->PC1_LO,
|
||||
&ACE->PC2_LO
|
||||
};
|
||||
|
||||
static uint32_t volatile * const sse_pc_hi_lut[NB_OF_ANALOG_BLOCKS] =
|
||||
{
|
||||
&ACE->PC0_HI,
|
||||
&ACE->PC1_HI,
|
||||
&ACE->PC2_HI
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_load_sse
|
||||
(
|
||||
sse_sequence_handle_t sequence
|
||||
)
|
||||
{
|
||||
ASSERT( sequence < (sse_sequence_handle_t)ACE_NB_OF_SSE_PROCEDURES );
|
||||
|
||||
if ( sequence < (sse_sequence_handle_t)ACE_NB_OF_SSE_PROCEDURES )
|
||||
{
|
||||
uint16_t i;
|
||||
uint16_t offset;
|
||||
const uint16_t * p_ucode;
|
||||
|
||||
ASSERT( g_sse_sequences_desc_table[sequence].sse_pc_id < NB_OF_ANALOG_BLOCKS );
|
||||
|
||||
if ( g_sse_sequences_desc_table[sequence].sse_pc_id < NB_OF_ANALOG_BLOCKS )
|
||||
{
|
||||
/* Stop relevant program counter. */
|
||||
*sse_pc_ctrl_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = SSE_STOP;
|
||||
|
||||
/* Load microcode into SEE RAM.*/
|
||||
p_ucode = g_sse_sequences_desc_table[sequence].sse_ucode;
|
||||
offset = g_sse_sequences_desc_table[sequence].sse_load_offset;
|
||||
|
||||
for ( i = 0u; i < g_sse_sequences_desc_table[sequence].sse_ucode_length; ++i )
|
||||
{
|
||||
ACE->SSE_RAM_DATA[offset + i] = (uint32_t)*p_ucode;
|
||||
++p_ucode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_start_sse
|
||||
(
|
||||
sse_sequence_handle_t sequence
|
||||
)
|
||||
{
|
||||
ASSERT( sequence < (sse_sequence_handle_t)ACE_NB_OF_SSE_PROCEDURES );
|
||||
|
||||
if ( sequence < (sse_sequence_handle_t)ACE_NB_OF_SSE_PROCEDURES )
|
||||
{
|
||||
uint16_t pc;
|
||||
|
||||
ASSERT( g_sse_sequences_desc_table[sequence].sse_pc_id < NB_OF_ANALOG_BLOCKS );
|
||||
ASSERT( g_sse_sequences_desc_table[sequence].sse_load_offset < SEE_RAM_WORD_SIZE );
|
||||
|
||||
pc = g_sse_sequences_desc_table[sequence].sse_load_offset;
|
||||
|
||||
if ( pc < 256u )
|
||||
{
|
||||
*sse_pc_lo_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = pc;
|
||||
}
|
||||
else
|
||||
{
|
||||
*sse_pc_hi_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = pc - 256;
|
||||
}
|
||||
|
||||
*sse_pc_ctrl_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = SSE_START;
|
||||
|
||||
/* Enable Sample Sequencing Engine in case it was not done as part of
|
||||
* system boot. */
|
||||
ACE->SSE_TS_CTRL |= TS_ENABLE_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_restart_sse
|
||||
(
|
||||
sse_sequence_handle_t sequence
|
||||
)
|
||||
{
|
||||
ASSERT( sequence < ACE_NB_OF_SSE_PROCEDURES );
|
||||
ASSERT( g_sse_sequences_desc_table[sequence].sse_pc_id < NB_OF_ANALOG_BLOCKS );
|
||||
ASSERT( g_sse_sequences_desc_table[sequence].sse_load_offset < SEE_RAM_WORD_SIZE );
|
||||
|
||||
if ( sequence < (sse_sequence_handle_t)ACE_NB_OF_SSE_PROCEDURES )
|
||||
{
|
||||
uint16_t pc;
|
||||
|
||||
pc = g_sse_sequences_desc_table[sequence].sse_loop_pc;
|
||||
|
||||
if ( pc < 256u )
|
||||
{
|
||||
*sse_pc_lo_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = pc;
|
||||
}
|
||||
else
|
||||
{
|
||||
*sse_pc_hi_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = pc - 256;
|
||||
}
|
||||
|
||||
*sse_pc_ctrl_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = SSE_START;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_stop_sse
|
||||
(
|
||||
sse_sequence_handle_t sequence
|
||||
)
|
||||
{
|
||||
ASSERT( sequence < ACE_NB_OF_SSE_PROCEDURES );
|
||||
|
||||
if ( sequence < (sse_sequence_handle_t)ACE_NB_OF_SSE_PROCEDURES )
|
||||
{
|
||||
/* Stop relevant program counter. */
|
||||
*sse_pc_ctrl_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = SSE_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_resume_sse
|
||||
(
|
||||
sse_sequence_handle_t sequence
|
||||
)
|
||||
{
|
||||
ASSERT( sequence < ACE_NB_OF_SSE_PROCEDURES );
|
||||
|
||||
if ( sequence < (sse_sequence_handle_t)ACE_NB_OF_SSE_PROCEDURES )
|
||||
{
|
||||
*sse_pc_ctrl_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = SSE_START;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_enable_sse_irq
|
||||
(
|
||||
sse_irq_id_t sse_irq_id
|
||||
)
|
||||
{
|
||||
ASSERT( sse_irq_id < NB_OF_SSE_FLAG_IRQS );
|
||||
|
||||
ACE->SSE_IRQ_EN |= 1uL << (uint32_t)sse_irq_id;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_disable_sse_irq
|
||||
(
|
||||
sse_irq_id_t sse_irq_id
|
||||
)
|
||||
{
|
||||
ASSERT( sse_irq_id < NB_OF_SSE_FLAG_IRQS );
|
||||
|
||||
ACE->SSE_IRQ_EN &= (uint32_t)~(1uL << (uint32_t)sse_irq_id);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_clear_sse_irq
|
||||
(
|
||||
sse_irq_id_t sse_irq_id
|
||||
)
|
||||
{
|
||||
ASSERT( sse_irq_id < NB_OF_SSE_FLAG_IRQS );
|
||||
|
||||
ACE->SSE_IRQ_CLR |= 1uL << (uint32_t)sse_irq_id;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_clear_sample_pipeline(void)
|
||||
{
|
||||
uint32_t saved_sse_ctrl;
|
||||
uint32_t saved_ppe_ctrl;
|
||||
|
||||
/* Pause the Sample Sequencing Engine. */
|
||||
saved_sse_ctrl = ACE->SSE_TS_CTRL;
|
||||
ACE->SSE_TS_CTRL = ACE->SSE_TS_CTRL & ~((uint32_t)TS_ENABLE_MASK);
|
||||
|
||||
/* Pause the Post Processing Engine. */
|
||||
saved_ppe_ctrl = ACE->PPE_CTRL;
|
||||
ACE->PPE_CTRL = ACE->PPE_CTRL & ~((uint32_t)PPE_ENABLE_MASK);
|
||||
|
||||
/* Reset the ADCs */
|
||||
ACE->ADC0_MISC_CTRL |= ADC_RESET_MASK;
|
||||
ACE->ADC1_MISC_CTRL |= ADC_RESET_MASK;
|
||||
ACE->ADC2_MISC_CTRL |= ADC_RESET_MASK;
|
||||
|
||||
/* Clear ADC FIFOs */
|
||||
ACE->ADC0_FIFO_CTRL |= ADC_FIFO_CLR_MASK;
|
||||
ACE->ADC1_FIFO_CTRL |= ADC_FIFO_CLR_MASK;
|
||||
ACE->ADC2_FIFO_CTRL |= ADC_FIFO_CLR_MASK;
|
||||
|
||||
/* clear DMA FIFOs */
|
||||
ACE->PPE_PDMA_CTRL |= PDMA_DATAOUT_CLR_MASK;
|
||||
|
||||
/* Unpause the Post Processing Engine. */
|
||||
ACE->PPE_CTRL = saved_ppe_ctrl;
|
||||
|
||||
/* Unpause the Sample Sequencing Engine. */
|
||||
ACE->SSE_TS_CTRL = saved_sse_ctrl;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,467 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2010 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* This file contains the implementation of the functions used to dynamically
|
||||
* control the linear transforms applied by the ACE post processing engine to
|
||||
* the samples read from the SSE.
|
||||
*
|
||||
* SVN $Revision: 2908 $
|
||||
* SVN $Date: 2010-08-20 16:01:28 +0100 (Fri, 20 Aug 2010) $
|
||||
*/
|
||||
|
||||
#include "mss_ace.h"
|
||||
#include "mss_ace_configurator.h"
|
||||
#include "mtd_data.h"
|
||||
#include "envm_layout.h"
|
||||
#include "../../CMSIS/a2fxxxm3.h"
|
||||
#include "../../CMSIS/mss_assert.h"
|
||||
#include "../../drivers_config/mss_ace/ace_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The ACE_set_linear_transform() is only available when using ACE configuration
|
||||
* files generated by Libero 9.1 or later.
|
||||
*/
|
||||
#ifdef ACE_CFG_DATA_FORMAT_VERSION
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Masks ans shift values used to derive the ABPS ranges from the analog block
|
||||
* configuration.
|
||||
*/
|
||||
#define ABPS1_CFG_BITS_MASK (uint32_t)0x06
|
||||
#define ABPS1_CFG_BITS_SHIFT (uint32_t)1
|
||||
|
||||
#define ABPS2_CFG_BITS_MASK (uint32_t)0x60
|
||||
#define ABPS2_CFG_BITS_SHIFT (uint32_t)5
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* One Bit DAC definitions.
|
||||
*/
|
||||
#define OBD_CURRENT (uint32_t)1
|
||||
#define OBD_VOLTAGE (uint32_t)0
|
||||
|
||||
#define OBD_MODE_MASK (uint32_t)0x01
|
||||
#define OBD_CHOPPING_MASK (uint32_t)0x02
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Neutral factor and offset for m*x + c trnasform.
|
||||
*/
|
||||
#define NEUTRAL_M_FACTOR 0x4000
|
||||
#define NEUTRAL_C_OFFSET 0x0000
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Enumearation of the various input channel types. This is used to differentiate
|
||||
between channel types in order to extract the relevant factory calibration
|
||||
data(m1 and c1).
|
||||
*/
|
||||
typedef enum channel_type
|
||||
{
|
||||
ABPS1_CHAN = 0,
|
||||
ABPS2_CHAN,
|
||||
CMB_CHAN,
|
||||
TMB_CHAN,
|
||||
DIRECT_ADC_INPUT_CHAN,
|
||||
OBDOUT_CHAN,
|
||||
FLOATING_CHAN
|
||||
} cal_channel_type_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
This data structure is used to store factory calibration data for a specific
|
||||
analog input.
|
||||
*/
|
||||
typedef struct __channel_calibration_t
|
||||
{
|
||||
uint16_t mext;
|
||||
uint16_t m1;
|
||||
uint16_t c1;
|
||||
} channel_calibration_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Local functions
|
||||
*/
|
||||
int32_t extend_sign
|
||||
(
|
||||
uint16_t x
|
||||
);
|
||||
|
||||
uint32_t adjust_to_24bit_ace_format
|
||||
(
|
||||
int64_t signed48
|
||||
);
|
||||
|
||||
uint32_t adjust_to_16bit_ace_format
|
||||
(
|
||||
int64_t signed48
|
||||
);
|
||||
|
||||
void get_calibration
|
||||
(
|
||||
adc_channel_id_t channel_id,
|
||||
channel_calibration_t * p_calibration
|
||||
);
|
||||
|
||||
void write_transform_coefficients
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
uint32_t m,
|
||||
uint32_t c
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
|
||||
*/
|
||||
extern const uint8_t g_ace_external_varef_used[ACE_NB_OF_ADC];
|
||||
|
||||
extern ace_channel_desc_t g_ace_channel_desc_table[ACE_NB_OF_INPUT_CHANNELS];
|
||||
|
||||
extern const ppe_transforms_desc_t g_ace_ppe_transforms_desc_table[ACE_NB_OF_INPUT_CHANNELS];
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Pointer to the manufacturing test data containing trimming information
|
||||
* generated during manufacturing.
|
||||
*/
|
||||
static const mtd_data_t * const p_mtd_data = (mtd_data_t *)MTD_ADDRESS;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
int16_t ACE_get_default_m_factor
|
||||
(
|
||||
ace_channel_handle_t channel_handle
|
||||
)
|
||||
{
|
||||
ASSERT( channel_handle < NB_OF_ACE_CHANNEL_HANDLES );
|
||||
|
||||
return g_ace_ppe_transforms_desc_table[channel_handle].m_ppe_offset;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
int16_t ACE_get_default_c_offset
|
||||
(
|
||||
ace_channel_handle_t channel_handle
|
||||
)
|
||||
{
|
||||
ASSERT( channel_handle < NB_OF_ACE_CHANNEL_HANDLES );
|
||||
|
||||
return g_ace_ppe_transforms_desc_table[channel_handle].c_ppe_offset;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
|
||||
m = m2 * m1 * mext
|
||||
c = (m2 * c1 * mext) + (c2 * mext)
|
||||
*/
|
||||
void ACE_set_linear_transform
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
int16_t m2,
|
||||
int16_t c2
|
||||
)
|
||||
{
|
||||
adc_channel_id_t channel_id;
|
||||
uint32_t m;
|
||||
uint32_t c;
|
||||
int32_t m32;
|
||||
int64_t m64;
|
||||
int32_t c32;
|
||||
int64_t c64_1;
|
||||
int64_t c64_2;
|
||||
uint16_t m1;
|
||||
uint16_t c1;
|
||||
uint16_t mext;
|
||||
|
||||
channel_calibration_t calibration;
|
||||
|
||||
ASSERT( channel_handle < NB_OF_ACE_CHANNEL_HANDLES );
|
||||
|
||||
if(channel_handle < NB_OF_ACE_CHANNEL_HANDLES)
|
||||
{
|
||||
channel_id = g_ace_channel_desc_table[channel_handle].signal_id;
|
||||
|
||||
get_calibration(channel_id, &calibration);
|
||||
|
||||
m1 = calibration.m1;
|
||||
c1 = calibration.c1;
|
||||
|
||||
mext = calibration.mext;
|
||||
|
||||
/*
|
||||
* m = m2 * m1 * mext
|
||||
*/
|
||||
m32 = extend_sign(m2) * extend_sign(m1);
|
||||
m64 = (int64_t)m32 * extend_sign(mext);
|
||||
|
||||
/* Convert 48-bit result to 32-bit ACE format result. */
|
||||
m = adjust_to_16bit_ace_format(m64);
|
||||
|
||||
/*
|
||||
* c = (m2 * c1 * mext) + (c2 * mext)
|
||||
*/
|
||||
c32 = extend_sign(m2) * extend_sign(c1);
|
||||
c64_1 = (int64_t)c32 * extend_sign(mext);
|
||||
|
||||
c64_2 = ((int64_t)(extend_sign(c2) * extend_sign(mext))) << 14;
|
||||
|
||||
c = adjust_to_24bit_ace_format(c64_1 + c64_2);
|
||||
|
||||
write_transform_coefficients(channel_handle, m, c);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Extend 16-bit signed number to 32-bit signed number.
|
||||
*/
|
||||
int32_t extend_sign
|
||||
(
|
||||
uint16_t x
|
||||
)
|
||||
{
|
||||
int32_t y;
|
||||
const uint32_t sign_bit_mask = 0x00008000u;
|
||||
|
||||
y = (x ^ sign_bit_mask) - sign_bit_mask;
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Take a 48-bit signed number, adjust it for saturation in the range -8 to
|
||||
+7.999, translate into 24-bit ACE format.
|
||||
*/
|
||||
uint32_t adjust_to_24bit_ace_format
|
||||
(
|
||||
int64_t signed48
|
||||
)
|
||||
{
|
||||
int32_t ace24_format;
|
||||
const int64_t MAX_POSITIVE = 0x00001FFFFFFFFFFFuLL; /* +7.9999 */
|
||||
const int64_t MIN_NEGATIVE = 0xFFFF200000000000uLL; /* -8 */
|
||||
|
||||
/* Check saturation. */
|
||||
if(signed48 > MAX_POSITIVE)
|
||||
{
|
||||
signed48 = MAX_POSITIVE;
|
||||
}
|
||||
else if(signed48 < MIN_NEGATIVE)
|
||||
{
|
||||
signed48 = MIN_NEGATIVE;
|
||||
}
|
||||
|
||||
/* Adjust to 24-bit ACE format. */
|
||||
ace24_format = (uint32_t)(signed48 >> 14);
|
||||
|
||||
return ace24_format;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Take a 48-bit signed number, adjust it for saturation in the range -8 to
|
||||
+7.999, translate into 16-bit ACE format.
|
||||
*/
|
||||
uint32_t adjust_to_16bit_ace_format
|
||||
(
|
||||
int64_t signed48
|
||||
)
|
||||
{
|
||||
int32_t ace24_format;
|
||||
const int64_t MAX_POSITIVE = 0x00001FFFFFFFFFFFuLL; /* +7.9999 */
|
||||
const int64_t MIN_NEGATIVE = 0xFFFF200000000000uLL; /* -8 */
|
||||
|
||||
/* Check saturation. */
|
||||
if(signed48 > MAX_POSITIVE)
|
||||
{
|
||||
signed48 = MAX_POSITIVE;
|
||||
}
|
||||
else if(signed48 < MIN_NEGATIVE)
|
||||
{
|
||||
signed48 = MIN_NEGATIVE;
|
||||
}
|
||||
|
||||
/* Adjust to 24-bit ACE format. */
|
||||
ace24_format = (uint32_t)(signed48 >> 20);
|
||||
|
||||
return ace24_format;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
|
||||
*/
|
||||
void get_calibration
|
||||
(
|
||||
adc_channel_id_t channel_id,
|
||||
channel_calibration_t * p_calibration
|
||||
)
|
||||
{
|
||||
const uint32_t channel_mask = 0x0000000F;
|
||||
const uint32_t CMB_MUX_SEL_MASK = 0x01;
|
||||
const uint32_t TMB_MUX_SEL_MASK = 0x01;
|
||||
|
||||
const cal_channel_type_t channel_type_lut[16] =
|
||||
{
|
||||
FLOATING_CHAN,
|
||||
ABPS1_CHAN,
|
||||
ABPS2_CHAN,
|
||||
CMB_CHAN,
|
||||
TMB_CHAN,
|
||||
ABPS1_CHAN,
|
||||
ABPS2_CHAN,
|
||||
CMB_CHAN,
|
||||
TMB_CHAN,
|
||||
DIRECT_ADC_INPUT_CHAN,
|
||||
DIRECT_ADC_INPUT_CHAN,
|
||||
DIRECT_ADC_INPUT_CHAN,
|
||||
DIRECT_ADC_INPUT_CHAN,
|
||||
FLOATING_CHAN,
|
||||
FLOATING_CHAN,
|
||||
OBDOUT_CHAN
|
||||
};
|
||||
|
||||
cal_channel_type_t channel_type;
|
||||
uint32_t channel_nb;
|
||||
uint32_t adc_nb;
|
||||
uint32_t range;
|
||||
uint32_t quad_id;
|
||||
mtd_calibration_mc_t const * p_mc_coeff = 0;
|
||||
|
||||
channel_nb = channel_id & channel_mask;
|
||||
channel_type = channel_type_lut[channel_nb];
|
||||
adc_nb = ((uint32_t)channel_id & 0x30u) >> 4u;
|
||||
|
||||
quad_id = adc_nb * 2;
|
||||
|
||||
if ( (channel_nb > 4) && (channel_nb < 9) ) { ++quad_id; }
|
||||
|
||||
switch ( channel_type )
|
||||
{
|
||||
case ABPS1_CHAN:
|
||||
range = (ACE->ACB_DATA[quad_id].b8 & ABPS1_CFG_BITS_MASK) >> ABPS1_CFG_BITS_SHIFT;
|
||||
p_mc_coeff = &p_mtd_data->abps_calibration[quad_id][0][range];
|
||||
break;
|
||||
|
||||
case ABPS2_CHAN:
|
||||
range = (ACE->ACB_DATA[quad_id].b8 & ABPS2_CFG_BITS_MASK) >> ABPS2_CFG_BITS_SHIFT;
|
||||
p_mc_coeff = &p_mtd_data->abps_calibration[quad_id][1][range];
|
||||
break;
|
||||
|
||||
case CMB_CHAN:
|
||||
{
|
||||
uint32_t cmb_mux_sel = (uint32_t)ACE->ACB_DATA[quad_id].b9 & CMB_MUX_SEL_MASK;
|
||||
if ( cmb_mux_sel == 0 )
|
||||
{ /* current monitor */
|
||||
p_mc_coeff = &p_mtd_data->cm_calibration[quad_id];
|
||||
}
|
||||
else
|
||||
{ /* direct input */
|
||||
p_mc_coeff = &p_mtd_data->quads_direct_input_cal[quad_id][0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TMB_CHAN:
|
||||
{
|
||||
uint32_t tmb_mux_sel = (uint32_t)ACE->ACB_DATA[quad_id].b10 & TMB_MUX_SEL_MASK;
|
||||
if ( tmb_mux_sel == 0 )
|
||||
{ /* temperature monitor */
|
||||
p_mc_coeff = &p_mtd_data->tm_calibration[quad_id];
|
||||
}
|
||||
else
|
||||
{ /* direct input */
|
||||
p_mc_coeff = &p_mtd_data->quads_direct_input_cal[quad_id][1];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DIRECT_ADC_INPUT_CHAN:
|
||||
{
|
||||
const uint32_t channel_to_direct_in_lut[16]
|
||||
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0};
|
||||
uint32_t direct_in_id;
|
||||
|
||||
direct_in_id = channel_to_direct_in_lut[channel_id & channel_mask];
|
||||
p_mc_coeff = &p_mtd_data->adc_direct_input_cal[adc_nb][direct_in_id];
|
||||
}
|
||||
break;
|
||||
|
||||
case OBDOUT_CHAN:
|
||||
{
|
||||
uint32_t obd_mode = (uint32_t)ACE->ACB_DATA[quad_id].b6 & OBD_MODE_MASK;
|
||||
uint32_t chopping_option = (uint32_t)ACE->ACB_DATA[quad_id].b6 & OBD_CHOPPING_MASK;
|
||||
if (obd_mode > 0)
|
||||
{
|
||||
obd_mode = 1;
|
||||
}
|
||||
if (chopping_option > 0)
|
||||
{
|
||||
chopping_option = 1;
|
||||
}
|
||||
p_mc_coeff = &p_mtd_data->obd_calibration[adc_nb][obd_mode][chopping_option];
|
||||
}
|
||||
break;
|
||||
|
||||
case FLOATING_CHAN:
|
||||
default:
|
||||
/* Give neutral values is invalid channel. */
|
||||
p_calibration->m1 = NEUTRAL_M_FACTOR;
|
||||
p_calibration->c1 = NEUTRAL_C_OFFSET;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_mc_coeff != 0)
|
||||
{
|
||||
p_calibration->m1 = p_mc_coeff->m;
|
||||
p_calibration->c1 = p_mc_coeff->c;
|
||||
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
Retrieve the value of the mext factor. This depends if external VAREF is
|
||||
used by the ADC sampling the analog input channel.
|
||||
*/
|
||||
if (g_ace_external_varef_used[adc_nb])
|
||||
{
|
||||
p_calibration->mext = p_mtd_data->global_settings.varef_m;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_calibration->mext = NEUTRAL_M_FACTOR;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Write new m and c transform factors into the PPE RAM. The m and c factors
|
||||
should be in 32-bit ACE number format. The factors will be merged with
|
||||
relevant PE opcode into PPE RAM. The 32-bit factors are shifted right by one
|
||||
byte giving a 24-bit ACE number which is then merged with an 8-bit PPE opcode
|
||||
located in the most significant byte of the PPE RAM location.
|
||||
*/
|
||||
void write_transform_coefficients
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
uint32_t m,
|
||||
uint32_t c
|
||||
)
|
||||
{
|
||||
uint16_t m_ppe_offset;
|
||||
uint16_t c_ppe_offset;
|
||||
const uint32_t PPE_OPCODE_MASK = 0xFF000000u;
|
||||
|
||||
m_ppe_offset = g_ace_ppe_transforms_desc_table[channel_handle].m_ppe_offset;
|
||||
c_ppe_offset = g_ace_ppe_transforms_desc_table[channel_handle].c_ppe_offset;
|
||||
|
||||
ACE->PPE_RAM_DATA[m_ppe_offset]
|
||||
= (ACE->PPE_RAM_DATA[m_ppe_offset] & PPE_OPCODE_MASK) | (m >> 8u);
|
||||
|
||||
ACE->PPE_RAM_DATA[c_ppe_offset]
|
||||
= (ACE->PPE_RAM_DATA[c_ppe_offset] & PPE_OPCODE_MASK) | (c >> 8u);
|
||||
}
|
||||
|
||||
#endif /* ACE_CFG_DATA_FORMAT_VERSION */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* SVN $Revision: 2905 $
|
||||
* SVN $Date: 2010-08-20 14:03:28 +0100 (Fri, 20 Aug 2010) $
|
||||
*/
|
||||
|
@ -16,7 +16,7 @@
|
|||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define START_ADC_CONVERSION 0x80uL
|
||||
|
||||
|
@ -31,8 +31,10 @@ void ace_init_convert(void);
|
|||
void ACE_init( void )
|
||||
{
|
||||
/* Initialize driver's internal data. */
|
||||
ace_init_flags();
|
||||
|
||||
#if (ACE_NB_OF_PPE_FLAGS > 0)
|
||||
ace_init_flags();
|
||||
#endif
|
||||
|
||||
/* Initialize the data structures used by conversion functions. */
|
||||
ace_init_convert();
|
||||
}
|
||||
|
@ -70,13 +72,13 @@ uint16_t ACE_get_adc_result
|
|||
uint32_t data_valid;
|
||||
|
||||
ASSERT( adc_id < NB_OF_ANALOG_MODULES );
|
||||
|
||||
|
||||
if ( adc_id < (uint8_t)NB_OF_ANALOG_MODULES )
|
||||
{
|
||||
do {
|
||||
data_valid = *adc_status_reg_lut[adc_id] & ADC_DATAVALID_MASK;
|
||||
} while ( !data_valid );
|
||||
|
||||
|
||||
result = (uint16_t)(*adc_status_reg_lut[adc_id] & ADC_RESULT_MASK);
|
||||
}
|
||||
return result;
|
||||
|
@ -88,7 +90,7 @@ uint16_t ACE_get_adc_result
|
|||
|
||||
#define SDD_ENABLE_MASK 0x20uL
|
||||
#define SDD_REG_SEL_MASK 0x40uL
|
||||
|
||||
|
||||
#define DAC0_SYNC_EN_MASK 0x10uL
|
||||
#define DAC1_SYNC_EN_MASK 0x20uL
|
||||
#define DAC2_SYNC_EN_MASK 0x40uL
|
||||
|
@ -149,7 +151,7 @@ void ACE_configure_sdd
|
|||
)
|
||||
{
|
||||
ASSERT( sdd_id < NB_OF_SDD );
|
||||
|
||||
|
||||
if ( sdd_id < NB_OF_SDD )
|
||||
{
|
||||
const uint8_t sdd_2_quad_lut[NB_OF_SDD] = {0u, 2u, 4u};
|
||||
|
@ -157,16 +159,16 @@ void ACE_configure_sdd
|
|||
uint8_t obd_mode_idx = 1u;
|
||||
uint8_t chopping_mode_idx = 0u;
|
||||
uint32_t saved_pc2_ctrl;
|
||||
|
||||
|
||||
quad_id = sdd_2_quad_lut[sdd_id];
|
||||
|
||||
|
||||
/* Pause the SSE PC2 while accesses to ACB from APB3 are taking place. */
|
||||
saved_pc2_ctrl = ACE->PC2_CTRL;
|
||||
ACE->PC2_CTRL = 0u;
|
||||
|
||||
|
||||
/* Select between voltage/current and RTZ modes.*/
|
||||
ACE->ACB_DATA[quad_id].b6 = mode;
|
||||
|
||||
|
||||
/* Load manufacturing generated trim value. */
|
||||
if ( (mode & OBD_MODE_MASK) > 0u )
|
||||
{
|
||||
|
@ -178,17 +180,17 @@ void ACE_configure_sdd
|
|||
}
|
||||
ACE->ACB_DATA[quad_id].b4
|
||||
= p_mtd_data->odb_trimming[sdd_id][obd_mode_idx][chopping_mode_idx];
|
||||
|
||||
|
||||
/* Restore SSE PC2 operations since no ACB accesses should take place
|
||||
* beyond this point. */
|
||||
ACE->PC2_CTRL = saved_pc2_ctrl;
|
||||
|
||||
|
||||
/* Set SDD resolution. */
|
||||
*dac_ctrl_reg_lut[sdd_id] = (uint32_t)resolution;
|
||||
|
||||
|
||||
/* Update SDD value through SSE_DACn_BYTES01. */
|
||||
*dac_ctrl_reg_lut[sdd_id] |= SDD_REG_SEL_MASK;
|
||||
|
||||
|
||||
/* Synchronous or individual SDD update. */
|
||||
if ( INDIVIDUAL_UPDATE == sync_update )
|
||||
{
|
||||
|
@ -210,7 +212,7 @@ void ACE_enable_sdd
|
|||
)
|
||||
{
|
||||
ASSERT( sdd_id < NB_OF_SDD );
|
||||
|
||||
|
||||
if ( sdd_id < NB_OF_SDD )
|
||||
{
|
||||
*dac_ctrl_reg_lut[sdd_id] |= SDD_ENABLE_MASK;
|
||||
|
@ -226,7 +228,7 @@ void ACE_disable_sdd
|
|||
)
|
||||
{
|
||||
ASSERT( sdd_id < NB_OF_SDD );
|
||||
|
||||
|
||||
if ( sdd_id < NB_OF_SDD )
|
||||
{
|
||||
*dac_ctrl_reg_lut[sdd_id] &= ~SDD_ENABLE_MASK;
|
||||
|
@ -243,7 +245,7 @@ void ACE_set_sdd_value
|
|||
)
|
||||
{
|
||||
ASSERT( sdd_id < NB_OF_SDD );
|
||||
|
||||
|
||||
if ( sdd_id < NB_OF_SDD )
|
||||
{
|
||||
*dac_byte2_reg_lut[sdd_id] = sdd_value >> 16;
|
||||
|
@ -262,9 +264,9 @@ void ACE_set_sdd_value_sync
|
|||
)
|
||||
{
|
||||
uint32_t dac_sync_ctrl;
|
||||
|
||||
|
||||
dac_sync_ctrl = ACE->DAC_SYNC_CTRL;
|
||||
|
||||
|
||||
if ( SDD_NO_UPDATE != sdd0_value )
|
||||
{
|
||||
ACE->DAC0_BYTE2 = sdd0_value >> 16;
|
||||
|
@ -286,7 +288,7 @@ void ACE_set_sdd_value_sync
|
|||
ACE->SSE_DAC2_BYTES01 = sdd2_value;
|
||||
dac_sync_ctrl |= DAC2_SYNC_UPDATE;
|
||||
}
|
||||
|
||||
|
||||
ACE->DAC_SYNC_CTRL = dac_sync_ctrl;
|
||||
}
|
||||
|
||||
|
@ -357,23 +359,23 @@ void ACE_set_comp_reference
|
|||
{
|
||||
uint8_t scb_id;
|
||||
uint32_t odd;
|
||||
|
||||
|
||||
odd = (uint32_t)comp_id & 0x01uL;
|
||||
|
||||
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
ASSERT( reference < NB_OF_COMP_REF );
|
||||
ASSERT( odd ); /* Only Temperature block comparators have configurable reference input. */
|
||||
|
||||
|
||||
if ( (comp_id < NB_OF_COMPARATORS) && (reference < NB_OF_COMP_REF) && (odd) )
|
||||
{
|
||||
uint32_t saved_pc2_ctrl;
|
||||
|
||||
|
||||
scb_id = comp_id_2_scb_lut[comp_id];
|
||||
|
||||
|
||||
/* Pause the SSE PC2 while accesses to ACB from APB3 are taking place. */
|
||||
saved_pc2_ctrl = ACE->PC2_CTRL;
|
||||
ACE->PC2_CTRL = 0u;
|
||||
|
||||
|
||||
if ( ADC_IN_COMP_REF == reference )
|
||||
{
|
||||
ACE->ACB_DATA[scb_id].b10 &= (uint8_t)~B10_COMP_VREF_SW_MASK;
|
||||
|
@ -384,7 +386,7 @@ void ACE_set_comp_reference
|
|||
ACE->ACB_DATA[scb_id].b10 &= (uint8_t)~B10_COMP_VREF_SW_MASK;
|
||||
ACE->ACB_DATA[scb_id].b11 = (ACE->ACB_DATA[scb_id].b11 & (uint8_t)~B11_DAC_MUXSEL_MASK) + (uint8_t)reference;
|
||||
}
|
||||
|
||||
|
||||
/* Restore SSE PC2 operations since no ACB accesses should take place
|
||||
* beyond this point. */
|
||||
ACE->PC2_CTRL = saved_pc2_ctrl;
|
||||
|
@ -401,22 +403,22 @@ void ACE_set_comp_hysteresis
|
|||
)
|
||||
{
|
||||
uint8_t scb_id;
|
||||
|
||||
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
ASSERT( hysteresis < NB_OF_HYSTERESIS );
|
||||
|
||||
|
||||
if ( (comp_id < NB_OF_COMPARATORS) && (hysteresis < NB_OF_HYSTERESIS) )
|
||||
{
|
||||
uint32_t odd;
|
||||
uint32_t saved_pc2_ctrl;
|
||||
|
||||
|
||||
scb_id = comp_id_2_scb_lut[comp_id];
|
||||
odd = (uint32_t)comp_id & 0x01uL;
|
||||
|
||||
|
||||
/* Pause the SSE PC2 while accesses to ACB from APB3 are taking place. */
|
||||
saved_pc2_ctrl = ACE->PC2_CTRL;
|
||||
ACE->PC2_CTRL = 0u;
|
||||
|
||||
|
||||
if ( odd )
|
||||
{
|
||||
/* Temperature monitor block comparator. */
|
||||
|
@ -427,7 +429,7 @@ void ACE_set_comp_hysteresis
|
|||
/* Current monitor block comparator. */
|
||||
ACE->ACB_DATA[scb_id].b9 = (ACE->ACB_DATA[scb_id].b9 & HYSTERESIS_MASK) | (uint8_t)((uint8_t)hysteresis << HYSTERESIS_SHIFT);
|
||||
}
|
||||
|
||||
|
||||
/* Restore SSE PC2 operations since no ACB accesses should take place
|
||||
* beyond this point. */
|
||||
ACE->PC2_CTRL = saved_pc2_ctrl;
|
||||
|
@ -435,7 +437,7 @@ void ACE_set_comp_hysteresis
|
|||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
|
||||
|
||||
*/
|
||||
void ACE_enable_comp
|
||||
(
|
||||
|
@ -443,21 +445,21 @@ void ACE_enable_comp
|
|||
)
|
||||
{
|
||||
uint8_t scb_id;
|
||||
|
||||
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
|
||||
if ( comp_id < NB_OF_COMPARATORS )
|
||||
{
|
||||
uint32_t odd;
|
||||
uint32_t saved_pc2_ctrl;
|
||||
|
||||
|
||||
scb_id = comp_id_2_scb_lut[comp_id];
|
||||
odd = (uint32_t)comp_id & 0x01uL;
|
||||
|
||||
|
||||
/* Pause the SSE PC2 while accesses to ACB from APB3 are taking place. */
|
||||
saved_pc2_ctrl = ACE->PC2_CTRL;
|
||||
ACE->PC2_CTRL = 0u;
|
||||
|
||||
|
||||
if ( odd )
|
||||
{
|
||||
/* Temperature monitor block comparator. */
|
||||
|
@ -468,7 +470,7 @@ void ACE_enable_comp
|
|||
/* Current monitor block comparator. */
|
||||
ACE->ACB_DATA[scb_id].b9 |= COMPARATOR_ENABLE_MASK;
|
||||
}
|
||||
|
||||
|
||||
/* Restore SSE PC2 operations since no ACB accesses should take place
|
||||
* beyond this point. */
|
||||
ACE->PC2_CTRL = saved_pc2_ctrl;
|
||||
|
@ -484,21 +486,21 @@ void ACE_disable_comp
|
|||
)
|
||||
{
|
||||
uint8_t scb_id;
|
||||
|
||||
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
|
||||
if ( comp_id < NB_OF_COMPARATORS )
|
||||
{
|
||||
uint32_t odd;
|
||||
uint32_t saved_pc2_ctrl;
|
||||
|
||||
|
||||
scb_id = comp_id_2_scb_lut[comp_id];
|
||||
odd = (uint32_t)comp_id & 0x01uL;
|
||||
|
||||
|
||||
/* Pause the SSE PC2 while accesses to ACB from APB3 are taking place. */
|
||||
saved_pc2_ctrl = ACE->PC2_CTRL;
|
||||
ACE->PC2_CTRL = 0u;
|
||||
|
||||
|
||||
if ( odd )
|
||||
{
|
||||
/* Temperature monitor block comparator. */
|
||||
|
@ -509,7 +511,7 @@ void ACE_disable_comp
|
|||
/* Current monitor block comparator. */
|
||||
ACE->ACB_DATA[scb_id].b9 &= (uint8_t)~COMPARATOR_ENABLE_MASK;
|
||||
}
|
||||
|
||||
|
||||
/* Restore SSE PC2 operations since no ACB accesses should take place
|
||||
* beyond this point. */
|
||||
ACE->PC2_CTRL = saved_pc2_ctrl;
|
||||
|
@ -539,7 +541,7 @@ void ACE_enable_comp_rise_irq
|
|||
)
|
||||
{
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
|
||||
ACE->COMP_IRQ_EN |= (FIRST_RISE_IRQ_MASK << (uint32_t)comp_id);
|
||||
}
|
||||
|
||||
|
@ -552,7 +554,7 @@ void ACE_disable_comp_rise_irq
|
|||
)
|
||||
{
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
|
||||
ACE->COMP_IRQ_EN &= ~(FIRST_RISE_IRQ_MASK << (uint32_t)comp_id);
|
||||
}
|
||||
|
||||
|
@ -565,7 +567,7 @@ void ACE_clear_comp_rise_irq
|
|||
)
|
||||
{
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
|
||||
ACE->COMP_IRQ_CLR |= (FIRST_RISE_IRQ_MASK << (uint32_t)comp_id);
|
||||
}
|
||||
|
||||
|
@ -578,7 +580,7 @@ void ACE_enable_comp_fall_irq
|
|||
)
|
||||
{
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
|
||||
ACE->COMP_IRQ_EN |= (FIRST_FALL_IRQ_MASK << (uint32_t)comp_id);
|
||||
}
|
||||
|
||||
|
@ -591,7 +593,7 @@ void ACE_disable_comp_fall_irq
|
|||
)
|
||||
{
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
|
||||
ACE->COMP_IRQ_EN &= ~(FIRST_FALL_IRQ_MASK << (uint32_t)comp_id);
|
||||
}
|
||||
|
||||
|
@ -604,7 +606,7 @@ void ACE_clear_comp_fall_irq
|
|||
)
|
||||
{
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
|
||||
ACE->COMP_IRQ_CLR |= (FIRST_FALL_IRQ_MASK << (uint32_t)comp_id);
|
||||
}
|
||||
|
||||
|
@ -643,9 +645,9 @@ ACE_get_first_channel
|
|||
)
|
||||
{
|
||||
ace_channel_handle_t channel_handle;
|
||||
|
||||
|
||||
channel_handle = (ace_channel_handle_t)0;
|
||||
|
||||
|
||||
return channel_handle;
|
||||
}
|
||||
|
||||
|
@ -659,12 +661,12 @@ ACE_get_next_channel
|
|||
)
|
||||
{
|
||||
++channel_handle;
|
||||
|
||||
|
||||
if ( channel_handle >= NB_OF_ACE_CHANNEL_HANDLES )
|
||||
{
|
||||
channel_handle = (ace_channel_handle_t)0;
|
||||
}
|
||||
|
||||
|
||||
return channel_handle;
|
||||
}
|
||||
|
||||
|
@ -679,7 +681,7 @@ ACE_get_channel_handle
|
|||
{
|
||||
uint16_t channel_idx;
|
||||
ace_channel_handle_t channel_handle = INVALID_CHANNEL_HANDLE;
|
||||
|
||||
|
||||
for ( channel_idx = 0u; channel_idx < (uint16_t)ACE_NB_OF_INPUT_CHANNELS; ++channel_idx )
|
||||
{
|
||||
if ( g_ace_channel_desc_table[channel_idx].p_sz_channel_name != 0 )
|
||||
|
@ -708,7 +710,7 @@ ACE_get_input_channel_handle
|
|||
{
|
||||
uint16_t channel_idx;
|
||||
ace_channel_handle_t channel_handle = INVALID_CHANNEL_HANDLE;
|
||||
|
||||
|
||||
for ( channel_idx = 0u; channel_idx < (uint16_t)ACE_NB_OF_INPUT_CHANNELS; ++channel_idx )
|
||||
{
|
||||
if ( g_ace_channel_desc_table[channel_idx].signal_id == channel_id )
|
||||
|
@ -732,10 +734,10 @@ ACE_get_ppe_sample
|
|||
{
|
||||
uint16_t sample;
|
||||
uint16_t ppe_offset;
|
||||
|
||||
|
||||
ppe_offset = g_ace_channel_desc_table[channel_handle].signal_ppe_offset;
|
||||
sample = (uint16_t)(ACE->PPE_RAM_DATA[ppe_offset] >> 16u);
|
||||
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -63,7 +63,7 @@ extern "C" {
|
|||
/* Allocating this many buffers will always ensure there is one free as, even
|
||||
though TX_RING_SIZE is set to two, the two Tx descriptors will only ever point
|
||||
to the same buffer. */
|
||||
#define macNUM_BUFFERS RX_RING_SIZE + TX_RING_SIZE + 1
|
||||
#define macNUM_BUFFERS RX_RING_SIZE + TX_RING_SIZE
|
||||
#define macBUFFER_SIZE 1488
|
||||
|
||||
/***************************************************************/
|
||||
|
@ -420,78 +420,94 @@ MSS_MAC_tx_packet
|
|||
configASSERT( usLength <= MSS_MAX_PACKET_SIZE );
|
||||
}
|
||||
|
||||
/* Check if second descriptor is free, if it is then the first must
|
||||
also be free. */
|
||||
if( ( ( (g_mss_mac.tx_descriptors[ 0 ].descriptor_0) & TDES0_OWN) == TDES0_OWN ) || ( ( (g_mss_mac.tx_descriptors[ 1 ].descriptor_0) & TDES0_OWN) == TDES0_OWN ) )
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
error = MAC_BUFFER_IS_FULL;
|
||||
/* Check both Tx descriptors are free, meaning the double send has completed. */
|
||||
if( ( ( (g_mss_mac.tx_descriptors[ 0 ].descriptor_0) & TDES0_OWN) == TDES0_OWN ) || ( ( (g_mss_mac.tx_descriptors[ 1 ].descriptor_0) & TDES0_OWN) == TDES0_OWN ) )
|
||||
{
|
||||
error = MAC_BUFFER_IS_FULL;
|
||||
}
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
|
||||
configASSERT( ( g_mss_mac.tx_desc_index == 0 ) );
|
||||
|
||||
if( error == MAC_OK )
|
||||
{
|
||||
/* Ensure nothing is going to get sent until both descriptors are ready.
|
||||
This is done to prevent a Tx end occurring prior to the second descriptor
|
||||
being ready. */
|
||||
MAC_BITBAND->CSR6_ST = 0u;
|
||||
|
||||
/* Assumed TX_RING_SIZE == 2. A #error directive checks this is the
|
||||
case. */
|
||||
for( ulDescriptor = 0; ulDescriptor < TX_RING_SIZE; ulDescriptor++ )
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 = 0u;
|
||||
|
||||
if( (g_mss_mac.flags & FLAG_CRC_DISABLE) != 0u ) {
|
||||
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 |= TDES1_AC;
|
||||
}
|
||||
|
||||
/* Every buffer can hold a full frame so they are always first and last
|
||||
descriptor */
|
||||
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 |= TDES1_LS | TDES1_FS | TDES1_IC;
|
||||
|
||||
/* set data size */
|
||||
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 |= usLength;
|
||||
|
||||
/* reset end of ring */
|
||||
g_mss_mac.tx_descriptors[TX_RING_SIZE-1].descriptor_1 |= TDES1_TER;
|
||||
|
||||
if( usLength > MSS_TX_BUFF_SIZE ) /* FLAG_EXCEED_LIMIT */
|
||||
for( ulDescriptor = 0; ulDescriptor < TX_RING_SIZE; ulDescriptor++ )
|
||||
{
|
||||
usLength = (uint16_t)MSS_TX_BUFF_SIZE;
|
||||
}
|
||||
|
||||
/* The data buffer is assigned to the Tx descriptor. */
|
||||
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].buffer_1 = ( unsigned long ) uip_buf;
|
||||
|
||||
/* update counters */
|
||||
desc = g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_0;
|
||||
if( (desc & TDES0_LO) != 0u ) {
|
||||
g_mss_mac.statistics.tx_loss_of_carrier++;
|
||||
}
|
||||
if( (desc & TDES0_NC) != 0u ) {
|
||||
g_mss_mac.statistics.tx_no_carrier++;
|
||||
}
|
||||
if( (desc & TDES0_LC) != 0u ) {
|
||||
g_mss_mac.statistics.tx_late_collision++;
|
||||
}
|
||||
if( (desc & TDES0_EC) != 0u ) {
|
||||
g_mss_mac.statistics.tx_excessive_collision++;
|
||||
}
|
||||
if( (desc & TDES0_UF) != 0u ) {
|
||||
g_mss_mac.statistics.tx_underflow_error++;
|
||||
}
|
||||
g_mss_mac.statistics.tx_collision_count +=
|
||||
(desc >> TDES0_CC_OFFSET) & TDES0_CC_MASK;
|
||||
|
||||
/* Give ownership of descriptor to the MAC */
|
||||
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_0 = RDES0_OWN;
|
||||
|
||||
g_mss_mac.tx_desc_index = (g_mss_mac.tx_desc_index + 1u) % (uint32_t)TX_RING_SIZE;
|
||||
|
||||
MAC_start_transmission();
|
||||
MAC->CSR1 = 1u;
|
||||
}
|
||||
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 = 0u;
|
||||
|
||||
if( (g_mss_mac.flags & FLAG_CRC_DISABLE) != 0u ) {
|
||||
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 |= TDES1_AC;
|
||||
}
|
||||
|
||||
/* Every buffer can hold a full frame so they are always first and last
|
||||
descriptor */
|
||||
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 |= TDES1_LS | TDES1_FS;
|
||||
|
||||
/* set data size */
|
||||
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 |= usLength;
|
||||
|
||||
/* reset end of ring */
|
||||
g_mss_mac.tx_descriptors[TX_RING_SIZE-1].descriptor_1 |= TDES1_TER;
|
||||
|
||||
if( usLength > MSS_TX_BUFF_SIZE ) /* FLAG_EXCEED_LIMIT */
|
||||
{
|
||||
usLength = (uint16_t)MSS_TX_BUFF_SIZE;
|
||||
}
|
||||
|
||||
/* The data buffer is assigned to the Tx descriptor. */
|
||||
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].buffer_1 = ( unsigned long ) uip_buf;
|
||||
|
||||
/* update counters */
|
||||
desc = g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_0;
|
||||
if( (desc & TDES0_LO) != 0u ) {
|
||||
g_mss_mac.statistics.tx_loss_of_carrier++;
|
||||
}
|
||||
if( (desc & TDES0_NC) != 0u ) {
|
||||
g_mss_mac.statistics.tx_no_carrier++;
|
||||
}
|
||||
if( (desc & TDES0_LC) != 0u ) {
|
||||
g_mss_mac.statistics.tx_late_collision++;
|
||||
}
|
||||
if( (desc & TDES0_EC) != 0u ) {
|
||||
g_mss_mac.statistics.tx_excessive_collision++;
|
||||
}
|
||||
if( (desc & TDES0_UF) != 0u ) {
|
||||
g_mss_mac.statistics.tx_underflow_error++;
|
||||
}
|
||||
g_mss_mac.statistics.tx_collision_count +=
|
||||
(desc >> TDES0_CC_OFFSET) & TDES0_CC_MASK;
|
||||
|
||||
/* Give ownership of descriptor to the MAC */
|
||||
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_0 = TDES0_OWN;
|
||||
|
||||
g_mss_mac.tx_desc_index = (g_mss_mac.tx_desc_index + 1u) % (uint32_t)TX_RING_SIZE;
|
||||
}
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
if (error == MAC_OK)
|
||||
{
|
||||
error = (int32_t)usLength;
|
||||
|
||||
/* Start sending now both descriptors are set up. This is done to
|
||||
prevent a Tx end occurring prior to the second descriptor being
|
||||
ready. */
|
||||
MAC_BITBAND->CSR6_ST = 1u;
|
||||
MAC->CSR1 = 1u;
|
||||
|
||||
/* The buffer pointed to by uip_buf is now assigned to a Tx descriptor.
|
||||
Find anothere free buffer for uip_buf. */
|
||||
uip_buf = MAC_obtain_buffer();
|
||||
|
@ -594,8 +610,7 @@ MSS_MAC_rx_packet
|
|||
* will keep trying to read till time_out expires or data is read, if MSS_MAC_BLOCKING
|
||||
* value is given as time_out, function will wait for the reception to complete.
|
||||
*
|
||||
* @param instance Pointer to a MAC_instance_t structure
|
||||
* @param pacData The pointer to the packet data.
|
||||
* @param pacData The pointer to the packet data.
|
||||
* @param time_out Time out value in milli seconds for receiving.
|
||||
* if value is #MSS_MAC_BLOCKING, there will be no time out.
|
||||
* if value is #MSS_MAC_NONBLOCKING, function will return immediately
|
||||
|
@ -1057,8 +1072,7 @@ MSS_MAC_prepare_rx_descriptor
|
|||
(desc & (CSR8_MFO_MASK|CSR8_MFC_MASK));
|
||||
|
||||
/* Give ownership of descriptor to the MAC */
|
||||
g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 =
|
||||
RDES0_OWN;
|
||||
g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 = RDES0_OWN;
|
||||
g_mss_mac.rx_desc_index = (g_mss_mac.rx_desc_index + 1u) % RX_RING_SIZE;
|
||||
|
||||
/* Start receive */
|
||||
|
@ -1431,10 +1445,19 @@ static void MAC_memcpy(uint8_t *dest, const uint8_t *src, uint32_t n)
|
|||
*/
|
||||
void MSS_MAC_FreeTxBuffers( void )
|
||||
{
|
||||
if( ( ( (g_mss_mac.tx_descriptors[ 0 ].descriptor_0) & TDES0_OWN) == 0 ) && ( ( (g_mss_mac.tx_descriptors[ 1 ].descriptor_0) & TDES0_OWN) == 0 ) )
|
||||
/* Check the buffers have not already been freed in the first of the
|
||||
two Tx interrupts - which could potentially happen if the second Tx completed
|
||||
during the interrupt for the first Tx. */
|
||||
if( g_mss_mac.tx_descriptors[ 0 ].buffer_1 != NULL )
|
||||
{
|
||||
MAC_release_buffer( ( unsigned char * ) g_mss_mac.tx_descriptors[ 0 ].buffer_1 );
|
||||
MAC_release_buffer( ( unsigned char * ) g_mss_mac.tx_descriptors[ 1 ].buffer_1 );
|
||||
if( ( ( (g_mss_mac.tx_descriptors[ 0 ].descriptor_0) & TDES0_OWN) == 0 ) && ( ( (g_mss_mac.tx_descriptors[ 1 ].descriptor_0) & TDES0_OWN) == 0 ) )
|
||||
{
|
||||
configASSERT( g_mss_mac.tx_descriptors[ 0 ].buffer_1 == g_mss_mac.tx_descriptors[ 1 ].buffer_1 );
|
||||
MAC_release_buffer( ( unsigned char * ) g_mss_mac.tx_descriptors[ 0 ].buffer_1 );
|
||||
|
||||
/* Just to mark the fact that the buffer has already been released. */
|
||||
g_mss_mac.tx_descriptors[ 0 ].buffer_1 == NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1447,19 +1470,72 @@ void MSS_MAC_FreeTxBuffers( void )
|
|||
*/
|
||||
unsigned char *MAC_obtain_buffer( void )
|
||||
{
|
||||
long lIndex;
|
||||
long lIndex, lAttempt = 0, lDescriptor, lBufferIsInUse;
|
||||
unsigned char *pcReturn = NULL;
|
||||
unsigned char *pcBufferAddress;
|
||||
|
||||
/* Find and return the address of a buffer that is not being used. Mark
|
||||
the buffer as now in use. */
|
||||
for( lIndex = 0; lIndex < macNUM_BUFFERS; lIndex++ )
|
||||
while( ( lAttempt <= 1 ) && ( pcReturn == NULL ) )
|
||||
{
|
||||
if( ucMACBufferInUse[ lIndex ] == pdFALSE )
|
||||
for( lIndex = 0; lIndex < macNUM_BUFFERS; lIndex++ )
|
||||
{
|
||||
pcReturn = &( xMACBuffers.ucBuffer[ lIndex ][ 0 ] );
|
||||
ucMACBufferInUse[ lIndex ] = pdTRUE;
|
||||
break;
|
||||
if( ucMACBufferInUse[ lIndex ] == pdFALSE )
|
||||
{
|
||||
pcReturn = &( xMACBuffers.ucBuffer[ lIndex ][ 0 ] );
|
||||
ucMACBufferInUse[ lIndex ] = pdTRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( pcReturn == NULL )
|
||||
{
|
||||
/* Did not find a buffer. That should not really happen, but could if
|
||||
an interrupt was missed. See if any buffers are marked as in use, but
|
||||
are not actually in use. */
|
||||
for( lIndex = 0; lIndex < macNUM_BUFFERS; lIndex++ )
|
||||
{
|
||||
pcBufferAddress = &( xMACBuffers.ucBuffer[ lIndex ][ 0 ] );
|
||||
lBufferIsInUse = pdFALSE;
|
||||
|
||||
/* Is the buffer used by an Rx descriptor? */
|
||||
for( lDescriptor = 0; lDescriptor < RX_RING_SIZE; lDescriptor++ )
|
||||
{
|
||||
if( g_mss_mac.rx_descriptors[ lDescriptor ].buffer_1 == ( uint32_t ) pcBufferAddress )
|
||||
{
|
||||
/* The buffer is in use by an Rx descriptor. */
|
||||
lBufferIsInUse = pdTRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( lBufferIsInUse != pdTRUE )
|
||||
{
|
||||
/* Is the buffer used by an Tx descriptor? */
|
||||
for( lDescriptor = 0; lDescriptor < TX_RING_SIZE; lDescriptor++ )
|
||||
{
|
||||
if( g_mss_mac.tx_descriptors[ lDescriptor ].buffer_1 == ( uint32_t ) pcBufferAddress )
|
||||
{
|
||||
/* The buffer is in use by an Tx descriptor. */
|
||||
lBufferIsInUse = pdTRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the buffer was not found to be in use by either a Tx or an
|
||||
Rx descriptor, but the buffer is marked as in use, then mark the
|
||||
buffer to be in it's correct state of "not in use". */
|
||||
if( ( lBufferIsInUse == pdFALSE ) && ( ucMACBufferInUse[ lIndex ] == pdTRUE ) )
|
||||
{
|
||||
ucMACBufferInUse[ lIndex ] = pdFALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If any buffer states were changed it might be that a buffer can now
|
||||
be obtained. Try again, but only one more time. */
|
||||
lAttempt++;
|
||||
}
|
||||
|
||||
configASSERT( pcReturn );
|
||||
|
|
|
@ -31,12 +31,14 @@ typedef uint32_t addr_t;
|
|||
/***************************************************************************//**
|
||||
* Descriptor structure
|
||||
*/
|
||||
#include "pack_struct_start.h"
|
||||
typedef struct {
|
||||
volatile uint32_t descriptor_0;
|
||||
volatile uint32_t descriptor_1;
|
||||
volatile uint32_t buffer_1;
|
||||
volatile uint32_t buffer_2;
|
||||
} MAC_descriptor_t;
|
||||
} MAC_descriptor_t
|
||||
#include "pack_struct_end.h"
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
|
@ -74,6 +76,7 @@ typedef struct {
|
|||
|
||||
uint8_t phy_address; /**< MII address of the connected PHY*/
|
||||
|
||||
#include "pack_struct_start.h"
|
||||
struct {
|
||||
uint32_t rx_interrupts; /**< Number of receive interrupts occurred.*/
|
||||
uint32_t rx_filtering_fail; /**< Number of received frames which did not pass
|
||||
|
@ -111,7 +114,8 @@ typedef struct {
|
|||
uint32_t tx_collision_count; /**< Number of collisions occurred.*/
|
||||
uint32_t tx_underflow_error; /**< Number of occurrences of; the FIFO was empty during
|
||||
the frame transmission.*/
|
||||
} statistics;
|
||||
} statistics
|
||||
#include "pack_struct_end.h"
|
||||
} MAC_instance_t
|
||||
#include "net/pack_struct_end.h"
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2007 Actel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* Actel:Firmware:MSS_Ethernet_MAC_Driver:2.0.103 configuration.
|
||||
*
|
||||
*/
|
||||
|
@ -17,7 +17,7 @@
|
|||
|
||||
#define BUS_ARBITRATION_SCHEME 0
|
||||
#define PROGRAMMABLE_BURST_LENGTH 0
|
||||
#define RX_RING_SIZE 4
|
||||
#define RX_RING_SIZE 5
|
||||
#define SETUP_FRAME_TIME_OUT 10000
|
||||
#define STATE_CHANGE_TIME_OUT 10000
|
||||
#define TX_RING_SIZE 2
|
||||
|
|
|
@ -1,413 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2008 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion microcontroller subsystem Peripheral DMA bare metal software
|
||||
* driver implementation.
|
||||
*
|
||||
* SVN $Revision: 2110 $
|
||||
* SVN $Date: 2010-02-05 15:24:19 +0000 (Fri, 05 Feb 2010) $
|
||||
*/
|
||||
#include "mss_pdma.h"
|
||||
#include "../../CMSIS/mss_assert.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void DMA_IRQHandler( void );
|
||||
#else
|
||||
void DMA_IRQHandler( void );
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
Offset of the posted writes WRITE_ADJ bits in a PDMA channel's configuration
|
||||
register.
|
||||
*/
|
||||
#define CHANNEL_N_POSTED_WRITE_ADJUST_SHIFT 14
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* Look-up table use to derice a channel's control register value from the
|
||||
* requested source/destination. This table is incexed on the pdma_src_dest_t
|
||||
* enumeration.
|
||||
*/
|
||||
#define CHANNEL_N_CTRL_PDMA_MASK (uint32_t)0x00000001
|
||||
#define CHANNEL_N_PERIPH_SELECT_SHIFT (uint32_t)23
|
||||
#define CHANNEL_N_DIRECTION_MASK (uint32_t)0x00000002
|
||||
|
||||
const uint32_t src_dest_to_ctrl_reg_lut[] =
|
||||
{
|
||||
CHANNEL_N_CTRL_PDMA_MASK, /* PDMA_FROM_UART_0 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)1 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK, /* PDMA_TO_UART_0 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)2 << CHANNEL_N_PERIPH_SELECT_SHIFT), /* PDMA_FROM_UART_1 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)3 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK, /* PDMA_TO_UART_1 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)4 << CHANNEL_N_PERIPH_SELECT_SHIFT), /* PDMA_FROM_SPI_0 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)5 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK, /* PDMA_TO_SPI_0 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)6 << CHANNEL_N_PERIPH_SELECT_SHIFT), /* PDMA_FROM_SPI_1 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)7 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK, /* PDMA_TO_SPI_1 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)8 << CHANNEL_N_PERIPH_SELECT_SHIFT), /* PDMA_FROM_FPGA_1 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)8 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK, /* PDMA_TO_FPGA_1 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)9 << CHANNEL_N_PERIPH_SELECT_SHIFT), /* PDMA_FROM_FPGA_0 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)9 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK, /* PDMA_TO_FPGA_0 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)10 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK, /* PDMA_TO_ACE */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)11 << CHANNEL_N_PERIPH_SELECT_SHIFT) /* PDMA_FROM_ACE */
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
#define PDMA_MASTER_ENABLE (uint32_t)0x04
|
||||
#define PDMA_SOFT_RESET (uint32_t)0x20
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
#define NB_OF_PDMA_CHANNELS 8
|
||||
|
||||
#define NEXT_CHANNEL_A 0U
|
||||
#define NEXT_CHANNEL_B 1U
|
||||
|
||||
#define CHANNEL_STOPPED 0U
|
||||
#define CHANNEL_STARTED 1U
|
||||
|
||||
static uint8_t g_pdma_next_channel[NB_OF_PDMA_CHANNELS];
|
||||
static uint8_t g_pdma_started_a[NB_OF_PDMA_CHANNELS];
|
||||
static uint8_t g_pdma_started_b[NB_OF_PDMA_CHANNELS];
|
||||
static pdma_channel_isr_t g_pdma_isr_table[NB_OF_PDMA_CHANNELS];
|
||||
static const uint16_t g_pdma_status_mask[NB_OF_PDMA_CHANNELS] =
|
||||
{
|
||||
(uint16_t)0x0003, /* PDMA_CHANNEL_0 */
|
||||
(uint16_t)0x000C, /* PDMA_CHANNEL_1 */
|
||||
(uint16_t)0x0030, /* PDMA_CHANNEL_2 */
|
||||
(uint16_t)0x00C0, /* PDMA_CHANNEL_3 */
|
||||
(uint16_t)0x0300, /* PDMA_CHANNEL_4 */
|
||||
(uint16_t)0x0C00, /* PDMA_CHANNEL_5 */
|
||||
(uint16_t)0x3000, /* PDMA_CHANNEL_6 */
|
||||
(uint16_t)0xC000, /* PDMA_CHANNEL_7 */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
void PDMA_init( void )
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
/* Enable PDMA master access to comms matrix. */
|
||||
SYSREG->AHB_MATRIX_CR |= PDMA_MASTER_ENABLE;
|
||||
|
||||
/* Reset PDMA block. */
|
||||
SYSREG->SOFT_RST_CR |= PDMA_SOFT_RESET;
|
||||
|
||||
/* Clear any previously pended MSS PDMA interrupt */
|
||||
NVIC_ClearPendingIRQ( DMA_IRQn );
|
||||
|
||||
/* Take PDMA controller out of reset*/
|
||||
SYSREG->SOFT_RST_CR &= ~PDMA_SOFT_RESET;
|
||||
|
||||
/* Initialize channels state information. */
|
||||
for ( i = 0; i < NB_OF_PDMA_CHANNELS; ++i )
|
||||
{
|
||||
g_pdma_next_channel[i] = NEXT_CHANNEL_A;
|
||||
g_pdma_started_a[i] = CHANNEL_STOPPED;
|
||||
g_pdma_started_b[i] = CHANNEL_STOPPED;
|
||||
g_pdma_isr_table[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
#define CHANNEL_RESET_MASK (uint32_t)0x00000020
|
||||
|
||||
void PDMA_configure
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
pdma_src_dest_t src_dest,
|
||||
uint32_t channel_cfg,
|
||||
uint8_t write_adjust
|
||||
)
|
||||
{
|
||||
/* Reset the channel. */
|
||||
PDMA->CHANNEL[channel_id].CRTL |= CHANNEL_RESET_MASK;
|
||||
PDMA->CHANNEL[channel_id].CRTL &= ~CHANNEL_RESET_MASK;
|
||||
|
||||
/* Configure PDMA channel's data source and destination. */
|
||||
if ( src_dest != PDMA_MEM_TO_MEM )
|
||||
{
|
||||
PDMA->CHANNEL[channel_id].CRTL |= src_dest_to_ctrl_reg_lut[src_dest];
|
||||
}
|
||||
|
||||
/* Configure PDMA channel trnasfer size, priority, source and destination address increment. */
|
||||
PDMA->CHANNEL[channel_id].CRTL |= channel_cfg;
|
||||
|
||||
/* Posted write adjust. */
|
||||
PDMA->CHANNEL[channel_id].CRTL |= ((uint32_t)write_adjust << CHANNEL_N_POSTED_WRITE_ADJUST_SHIFT);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
#define PAUSE_MASK (uint32_t)0x00000010
|
||||
|
||||
#define BUFFER_B_SELECT_MASK (uint32_t)0x00000004
|
||||
|
||||
#define CLEAR_PORT_A_DONE_MASK (uint32_t)0x00000080
|
||||
#define CLEAR_PORT_B_DONE_MASK (uint32_t)0x00000100
|
||||
|
||||
#define PORT_A_COMPLETE_MASK (uint32_t)0x00000001
|
||||
#define PORT_B_COMPLETE_MASK (uint32_t)0x00000002
|
||||
|
||||
void PDMA_start
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
uint32_t src_addr,
|
||||
uint32_t dest_addr,
|
||||
uint16_t transfer_count
|
||||
)
|
||||
{
|
||||
/* Pause transfer. */
|
||||
PDMA->CHANNEL[channel_id].CRTL |= PAUSE_MASK;
|
||||
|
||||
/* Clear complete transfers. */
|
||||
if ( PDMA->CHANNEL[channel_id].STATUS & PORT_A_COMPLETE_MASK )
|
||||
{
|
||||
PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_A_DONE_MASK;
|
||||
g_pdma_started_a[channel_id] = CHANNEL_STOPPED;
|
||||
}
|
||||
if ( PDMA->CHANNEL[channel_id].STATUS & PORT_B_COMPLETE_MASK )
|
||||
{
|
||||
PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_B_DONE_MASK;
|
||||
g_pdma_started_b[channel_id] = CHANNEL_STOPPED;
|
||||
}
|
||||
|
||||
/* Load source, destination and transfer count. */
|
||||
if ( PDMA->CHANNEL[channel_id].STATUS & BUFFER_B_SELECT_MASK )
|
||||
{
|
||||
g_pdma_next_channel[channel_id] = NEXT_CHANNEL_A;
|
||||
g_pdma_started_b[channel_id] = CHANNEL_STARTED;
|
||||
|
||||
PDMA->CHANNEL[channel_id].BUFFER_B_SRC_ADDR = src_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_B_DEST_ADDR = dest_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_B_TRANSFER_COUNT = transfer_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pdma_next_channel[channel_id] = NEXT_CHANNEL_B;
|
||||
g_pdma_started_a[channel_id] = CHANNEL_STARTED;
|
||||
|
||||
PDMA->CHANNEL[channel_id].BUFFER_A_SRC_ADDR = src_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_A_DEST_ADDR = dest_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_A_TRANSFER_COUNT = transfer_count;
|
||||
}
|
||||
|
||||
/* Start transfer */
|
||||
PDMA->CHANNEL[channel_id].CRTL &= ~PAUSE_MASK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
void PDMA_load_next_buffer
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
uint32_t src_addr,
|
||||
uint32_t dest_addr,
|
||||
uint16_t transfer_count
|
||||
)
|
||||
{
|
||||
if ( NEXT_CHANNEL_A == g_pdma_next_channel[channel_id] )
|
||||
{
|
||||
/* Wait for channel A current transfer completion. */
|
||||
if ( CHANNEL_STARTED == g_pdma_started_a[channel_id] )
|
||||
{
|
||||
uint32_t completed;
|
||||
uint32_t channel_mask;
|
||||
channel_mask = (uint32_t)1 << ((uint32_t)channel_id * 2U);
|
||||
do {
|
||||
completed = PDMA->BUFFER_STATUS & channel_mask;
|
||||
} while( !completed );
|
||||
PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_A_DONE_MASK;
|
||||
}
|
||||
/* Load source, destination and transfer count. */
|
||||
PDMA->CHANNEL[channel_id].BUFFER_A_SRC_ADDR = src_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_A_DEST_ADDR = dest_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_A_TRANSFER_COUNT = transfer_count;
|
||||
|
||||
/* Update channel state information. */
|
||||
g_pdma_next_channel[channel_id] = NEXT_CHANNEL_B;
|
||||
g_pdma_started_a[channel_id] = CHANNEL_STARTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wait for channel B current transfer completion. */
|
||||
if ( CHANNEL_STARTED == g_pdma_started_b[channel_id] )
|
||||
{
|
||||
uint32_t completed;
|
||||
uint32_t channel_mask;
|
||||
channel_mask = (uint32_t)1 << (((uint32_t)channel_id * 2U) + 1U);
|
||||
do {
|
||||
completed = PDMA->BUFFER_STATUS & channel_mask;
|
||||
} while( !completed );
|
||||
PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_B_DONE_MASK;
|
||||
}
|
||||
/* Load source, destination and transfer count. */
|
||||
PDMA->CHANNEL[channel_id].BUFFER_B_SRC_ADDR = src_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_B_DEST_ADDR = dest_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_B_TRANSFER_COUNT = transfer_count;
|
||||
|
||||
/* Update channel state information. */
|
||||
g_pdma_next_channel[channel_id] = NEXT_CHANNEL_A;
|
||||
g_pdma_started_b[channel_id] = CHANNEL_STARTED;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
uint32_t PDMA_status
|
||||
(
|
||||
pdma_channel_id_t channel_id
|
||||
)
|
||||
{
|
||||
uint32_t status;
|
||||
|
||||
status = PDMA->CHANNEL[channel_id].STATUS & (PORT_A_COMPLETE_MASK | PORT_B_COMPLETE_MASK);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
*
|
||||
*/
|
||||
#define CHANNEL_0_STATUS_BITS_MASK (uint16_t)0x0003
|
||||
#define CHANNEL_1_STATUS_BITS_MASK (uint16_t)0x000C
|
||||
#define CHANNEL_2_STATUS_BITS_MASK (uint16_t)0x0030
|
||||
#define CHANNEL_3_STATUS_BITS_MASK (uint16_t)0x00C0
|
||||
#define CHANNEL_4_STATUS_BITS_MASK (uint16_t)0x0300
|
||||
#define CHANNEL_5_STATUS_BITS_MASK (uint16_t)0x0C00
|
||||
#define CHANNEL_6_STATUS_BITS_MASK (uint16_t)0x3000
|
||||
#define CHANNEL_7_STATUS_BITS_MASK (uint16_t)0xC000
|
||||
|
||||
static pdma_channel_id_t get_channel_id_from_status
|
||||
(
|
||||
uint16_t status
|
||||
)
|
||||
{
|
||||
pdma_channel_id_t channel_id = PDMA_CHANNEL_0;
|
||||
|
||||
if ( status & CHANNEL_0_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_0;
|
||||
}
|
||||
else if ( status & CHANNEL_1_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_1;
|
||||
}
|
||||
else if ( status & CHANNEL_2_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_2;
|
||||
}
|
||||
else if ( status & CHANNEL_3_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_3;
|
||||
}
|
||||
else if ( status & CHANNEL_4_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_4;
|
||||
}
|
||||
else if ( status & CHANNEL_5_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_5;
|
||||
}
|
||||
else if ( status & CHANNEL_6_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_6;
|
||||
}
|
||||
else if ( status & CHANNEL_7_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_7;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(0);
|
||||
}
|
||||
return channel_id;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
*
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void DMA_IRQHandler( void )
|
||||
#else
|
||||
void DMA_IRQHandler( void )
|
||||
#endif
|
||||
{
|
||||
uint16_t status;
|
||||
pdma_channel_id_t channel_id;
|
||||
|
||||
status = (uint16_t)PDMA->BUFFER_STATUS;
|
||||
|
||||
do {
|
||||
channel_id = get_channel_id_from_status( status );
|
||||
status &= (uint16_t)~g_pdma_status_mask[channel_id];
|
||||
if ( 0 != g_pdma_isr_table[channel_id])
|
||||
{
|
||||
g_pdma_isr_table[channel_id]();
|
||||
}
|
||||
} while ( 0U != status );
|
||||
|
||||
NVIC_ClearPendingIRQ( DMA_IRQn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
void PDMA_set_irq_handler
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
pdma_channel_isr_t handler
|
||||
)
|
||||
{
|
||||
/* Save address of handler function in PDMA driver ISR lookup table. */
|
||||
g_pdma_isr_table[channel_id] = handler;
|
||||
|
||||
/* Enable PDMA channel's interrupt. */
|
||||
PDMA->CHANNEL[channel_id].CRTL |= PDMA_IRQ_ENABLE_MASK;
|
||||
|
||||
/* Enable PDMA interrupt in Cortex-M3 NVIC. */
|
||||
NVIC_EnableIRQ( DMA_IRQn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
void PDMA_enable_irq( pdma_channel_id_t channel_id )
|
||||
{
|
||||
PDMA->CHANNEL[channel_id].CRTL |= PDMA_IRQ_ENABLE_MASK;
|
||||
NVIC_EnableIRQ( DMA_IRQn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
void PDMA_clear_irq
|
||||
(
|
||||
pdma_channel_id_t channel_id
|
||||
)
|
||||
{
|
||||
/* Clear interrupt in PDMA controller. */
|
||||
PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_A_DONE_MASK;
|
||||
PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_B_DONE_MASK;
|
||||
|
||||
/* Clear interrupt in Cortex-M3 NVIC. */
|
||||
NVIC_ClearPendingIRQ( DMA_IRQn );
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,703 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2008 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion microcontroller subsystem Peripheral DMA bare metal software
|
||||
* driver public API.
|
||||
*
|
||||
* SVN $Revision: 2110 $
|
||||
* SVN $Date: 2010-02-05 15:24:19 +0000 (Fri, 05 Feb 2010) $
|
||||
*/
|
||||
/*=========================================================================*//**
|
||||
@mainpage SmartFusion MSS GPIO Bare Metal Driver.
|
||||
|
||||
@section intro_sec Introduction
|
||||
The SmartFusion Microcontroller Subsystem (MSS) includes an 8 channel
|
||||
Peripheral DMA (PDMA) controller.
|
||||
This software driver provides a set of functions for controlling the MSS PDMA
|
||||
controller as part of a bare metal system where no operating system is available.
|
||||
This driver can be adapted for use as part of an operating system but the
|
||||
implementation of the adaptation layer between this driver and the operating
|
||||
system's driver model is outside the scope of this driver.
|
||||
|
||||
@section theory_op Theory of Operation
|
||||
The MSS PDMA driver uses the SmartFusion "Cortex Microcontroler Software
|
||||
Interface Standard - Peripheral Access Layer" (CMSIS-PAL) to access MSS hardware
|
||||
registers. You must ensure that the SmartFusion CMSIS-PAL is either included
|
||||
in the software toolchain used to build your project or is included in your
|
||||
project. The most up-to-date SmartFusion CMSIS-PAL files can be obtained using
|
||||
the Actel Firmware Catalog.
|
||||
|
||||
The MSS PDMA driver functions are grouped into the following categories:
|
||||
- Initialization
|
||||
- Configuration
|
||||
- DMA transfer control
|
||||
- Interrupt control
|
||||
|
||||
The MSS PDMA driver is initialized through a call to the PDMA_init() function.
|
||||
The PDMA_init() function must be called before any other PDMA driver functions
|
||||
can be called.
|
||||
|
||||
Each PDMA channel is individually configured through a call to the PDMA_configure()
|
||||
function. Configuration includes:
|
||||
- channel priority
|
||||
- transfer size
|
||||
- source and/or destination address increment
|
||||
- source or destination of the DMA transfer
|
||||
PDMA channels can be divided into high and low priority channels. High priority
|
||||
channels are given more opportunities to perform transfers than low priority
|
||||
channels when there are continuous high priority channels requests. The ratio
|
||||
of high priority to low priority PDMA transfers is configurable through the
|
||||
PDMA_set_priority() function.
|
||||
PDMA channels can be configured to perform byte (8 bits), half-word (16 bits)
|
||||
or word (32 bits) transfers.
|
||||
The source and destination address of a PDMA channel’s transfers can be
|
||||
independently configured to increment by 0, 1, 2 or 4 bytes. For example, the
|
||||
content of a byte buffer located in RAM can be transferred into a peripheral’s
|
||||
transmit register by configuring the source address increment to one byte and
|
||||
no increment of the destination address.
|
||||
The source or destination of a PDMA channel’s transfers can be configured to
|
||||
be one of the MSS peripherals. This allows the PDMA controller to use some
|
||||
hardware flow control signaling with the peripheral to avoid overrunning the
|
||||
peripheral’s data buffer when the peripheral is the destination of the DMA
|
||||
transfer, or attempting to read data from the peripheral while it is not ready
|
||||
when the peripheral is the source of the transfer.
|
||||
A PDMA channel can also be configured to transfer data between two memory
|
||||
mapped locations (memory to memory). No hardware flow control is used by the
|
||||
PDMA controller for data transfer in this configuration.
|
||||
|
||||
A DMA transfer can be initiated by a call to the PDMA_start() function after a
|
||||
PDMA channel has been configured. Once started, further data can be pushed
|
||||
through the PDMA channel by calling the PDMA_load_next_buffer() function. The
|
||||
PDMA_load_next_buffer() function can be called every time a call to the
|
||||
PDMA_status() function indicates that the PDMA channel used for the transfer
|
||||
has a free buffer or it can be called as a result of a PDMA interrupt.
|
||||
|
||||
A DMA transfer can be paused and resumed through calls to functions PDMA_pause()
|
||||
and PDMA_resume().
|
||||
|
||||
Your application can manage DMA transfers using interrupts through the use of
|
||||
the following functions:
|
||||
- PDMA_set_irq_handler()
|
||||
- PDMA_enable_irq()
|
||||
- PDMA_clear_irq()
|
||||
- PDMA_disable_irq()
|
||||
The PDMA_set_irq_handler() function is used to register PDMA channel interrupt
|
||||
handler functions with the driver. You must create and register an interrupt
|
||||
handler function for each interrupt driven PDMA channel used by the application.
|
||||
Use the PDMA_enable_irq() function to enable interrupts for the PDMA channels.
|
||||
Every time a PDMA channel completes the transfer of a buffer it causes a PDMA
|
||||
interrupt to occur and the PDMA driver will call the interrupt handler
|
||||
registered by the application for that PDMA channel.
|
||||
|
||||
*//*=========================================================================*/
|
||||
#ifndef __MSS_PERIPHERAL_DMA_H_
|
||||
#define __MSS_PERIPHERAL_DMA_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../../CMSIS/a2fxxxm3.h"
|
||||
|
||||
/***************************************************************************//**
|
||||
The pdma_channel_id_t enumeration is used to identify peripheral DMA channels.
|
||||
It is used as function parameter to specify the PDMA channel used.
|
||||
*/
|
||||
typedef enum __pdma_channel_id
|
||||
{
|
||||
PDMA_CHANNEL_0 = 0,
|
||||
PDMA_CHANNEL_1,
|
||||
PDMA_CHANNEL_2,
|
||||
PDMA_CHANNEL_3,
|
||||
PDMA_CHANNEL_4,
|
||||
PDMA_CHANNEL_5,
|
||||
PDMA_CHANNEL_6,
|
||||
PDMA_CHANNEL_7
|
||||
} pdma_channel_id_t;
|
||||
|
||||
/***************************************************************************//**
|
||||
The pdma_src_dest_t enumeration is used to specify the source or destination
|
||||
of transfers on a PDMA channel. It specifies which hardware peripheral will be
|
||||
the source or destination of DMA transfers. This allows the PDMA controller
|
||||
to use hardware flow control signals to avoid overrunning a
|
||||
destination peripheral with data it is not ready to receive, or attempting to
|
||||
transfer data from a peripheral while it has no data ready to transfer.
|
||||
The pdma_src_dest_t enumeration can also be used to specify that a PDMA channel
|
||||
is configured to transfer data between two memory mapped locations
|
||||
(memory to memory). No hardware data flow control is used by the PDMA
|
||||
controller in this configuration.
|
||||
This enumeration is used as parameter to function PDMA_configure().
|
||||
*/
|
||||
typedef enum __pdma_src_dest
|
||||
{
|
||||
PDMA_FROM_UART_0 = 0,
|
||||
PDMA_TO_UART_0,
|
||||
PDMA_FROM_UART_1,
|
||||
PDMA_TO_UART_1,
|
||||
PDMA_FROM_SPI_0,
|
||||
PDMA_TO_SPI_0,
|
||||
PDMA_FROM_SPI_1,
|
||||
PDMA_TO_SPI_1,
|
||||
PDMA_FROM_FPGA_1,
|
||||
PDMA_TO_FPGA_1,
|
||||
PDMA_FROM_FPGA_0,
|
||||
PDMA_TO_FPGA_0,
|
||||
PDMA_TO_ACE,
|
||||
PDMA_FROM_ACE,
|
||||
PDMA_MEM_TO_MEM
|
||||
} pdma_src_dest_t;
|
||||
|
||||
/***************************************************************************//**
|
||||
The pdma_priority_ratio_t enumeration is used to configure the ratio of high
|
||||
priority to low priority PDMA channels. This ratio specifies how many DMA
|
||||
transfer opportunities will be given to high priority channels before a DMA
|
||||
transfer opportunity is given to a low priority channel when there are
|
||||
continuous requests from high priority channels. This enumeration is used as
|
||||
parameter to function PDMA_set_priority_ratio().
|
||||
*/
|
||||
typedef enum __pdma_priority_ratio_t
|
||||
{
|
||||
PDMA_ROUND_ROBIN = 0,
|
||||
PDMA_RATIO_HIGH_LOW_1_TO_1 = 1,
|
||||
PDMA_RATIO_HIGH_LOW_3_TO_1 = 3,
|
||||
PDMA_RATIO_HIGH_LOW_7_TO_1 = 7,
|
||||
PDMA_RATIO_HIGH_LOW_15_TO_1 = 15,
|
||||
PDMA_RATIO_HIGH_LOW_31_TO_1 = 31,
|
||||
PDMA_RATIO_HIGH_LOW_63_TO_1 = 63,
|
||||
PDMA_RATIO_HIGH_LOW_127_TO_1 = 127,
|
||||
PDMA_RATIO_HIGH_LOW_255_TO_1 = 255
|
||||
} pdma_priority_ratio_t;
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
The pdma_channel_isr_t type is a pointer to a PDMA channel interrupt handler
|
||||
function. It specifies the function prototype of functions that can be
|
||||
registered as PDMA channel interrupt handlers. It is used as parameter to
|
||||
function PDMA_set_irq_handler().
|
||||
*/
|
||||
typedef void (*pdma_channel_isr_t)( void );
|
||||
/***************************************************************************//**
|
||||
These constants are used to build the channel_cfg parameter of the
|
||||
PDMA_configure() function. They specify whether a channel is a high or low
|
||||
priority channel.
|
||||
*/
|
||||
#define PDMA_LOW_PRIORITY 0x0000
|
||||
#define PDMA_HIGH_PRIORITY 0x0200
|
||||
|
||||
/***************************************************************************//**
|
||||
These constants are used to build the channel_cfg parameter of the
|
||||
PDMA_configure() function. They specify the data width of the transfers
|
||||
performed by a PDMA channel.
|
||||
*/
|
||||
#define PDMA_BYTE_TRANSFER 0x0000 /* Byte transfers (8 bits) */
|
||||
#define PDMA_HALFWORD_TRANSFER 0x0004 /* Half-word transfers (16 bits) */
|
||||
#define PDMA_WORD_TRANSFER 0x0008 /* Word transfers (32 bits) */
|
||||
|
||||
/***************************************************************************//**
|
||||
These constants are used to build the channel_cfg parameter of the
|
||||
PDMA_configure() function. They specify the PDMA channel’s source and
|
||||
destination address increment.
|
||||
*/
|
||||
#define PDMA_NO_INC 0
|
||||
#define PDMA_INC_SRC_ONE_BYTE 0x0400
|
||||
#define PDMA_INC_SRC_TWO_BYTES 0x0800
|
||||
#define PDMA_INC_SRC_FOUR_BYTES 0x0C00
|
||||
#define PDMA_INC_DEST_ONE_BYTE 0x1000
|
||||
#define PDMA_INC_DEST_TWO_BYTES 0x2000
|
||||
#define PDMA_INC_DEST_FOUR_BYTES 0x3000
|
||||
|
||||
/***************************************************************************//**
|
||||
* Mask for various control register bits.
|
||||
*/
|
||||
#define PDMA_IRQ_ENABLE_MASK (uint32_t)0x00000040
|
||||
#define PDMA_PAUSE_MASK (uint32_t)0x00000010
|
||||
|
||||
/***************************************************************************//**
|
||||
These constants are used to specify the src_addr parameter to the PDMA_start()
|
||||
and PDMA_load_next_buffer() functions. They specify the receive register
|
||||
address of peripherals that can be the source of a DMA transfer.
|
||||
When a PDMA channel is configured for DMA transfers from a peripheral to memory,
|
||||
the constant specifying that peripheral’s receive register address must be used
|
||||
as the src_addr parameter.
|
||||
*/
|
||||
#define PDMA_SPI0_RX_REGISTER 0x40001010uL
|
||||
#define PDMA_SPI1_RX_REGISTER 0x40011010uL
|
||||
#define PDMA_UART0_RX_REGISTER 0x40000000uL
|
||||
#define PDMA_UART1_RX_REGISTER 0x40010000uL
|
||||
#define PDMA_ACE_PPE_DATAOUT 0x40021308uL
|
||||
|
||||
/***************************************************************************//**
|
||||
These constants are used to specify the dest_addr parameter to the PDMA_start()
|
||||
and PDMA_load_next_buffer() functions. They specify the transmit register
|
||||
address of peripherals that can be the destination of a DMA transfer.
|
||||
When a PDMA channel is configured for DMA transfers from memory to a peripheral,
|
||||
the constant specifying that peripheral’s transmit register address must be used
|
||||
as the dest_addr parameter.
|
||||
*/
|
||||
#define PDMA_SPI0_TX_REGISTER 0x40001014uL
|
||||
#define PDMA_SPI1_TX_REGISTER 0x40011014uL
|
||||
#define PDMA_UART0_TX_REGISTER 0x40000000uL
|
||||
#define PDMA_UART1_TX_REGISTER 0x40010000uL
|
||||
#define PDMA_ACE_SSE_DATAIN 0x40020700uL
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_DEFAULT_WRITE_ADJ constant provides a suitable default value for the
|
||||
PDMA_configure() function write_adjust parameter.
|
||||
*/
|
||||
#define PDMA_DEFAULT_WRITE_ADJ 10u
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_init() function initializes the peripheral DMA hardware and driver
|
||||
internal data. It resets the PDMA and it also clears any pending PDMA
|
||||
interrupts in the Cortex-M3 interrupt controller. When the function exits, it
|
||||
takes the PDMA block out of reset.
|
||||
*/
|
||||
void PDMA_init( void );
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_configure() function configures a PDMA channel.
|
||||
It specifies:
|
||||
- The peripheral which will be the source or destination of the DMA transfer.
|
||||
- Whether the DMA channel will be a high or low priority channel
|
||||
- The source and destination address increment that will take place after
|
||||
each transfer.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
|
||||
@param src_dest
|
||||
The src_dest parameter specifies the source or destination of the DMA
|
||||
transfers that will be performed. It can be one of the following:
|
||||
- PDMA_FROM_UART_0
|
||||
- PDMA_TO_UART_0
|
||||
- PDMA_FROM_UART_1
|
||||
- PDMA_TO_UART_1
|
||||
- PDMA_FROM_SPI_0
|
||||
- PDMA_TO_SPI_0
|
||||
- PDMA_FROM_SPI_1
|
||||
- PDMA_TO_SPI_1
|
||||
- PDMA_FROM_FPGA_1
|
||||
- PDMA_TO_FPGA_1
|
||||
- PDMA_FROM_FPGA_0
|
||||
- PDMA_TO_FPGA_0
|
||||
- PDMA_TO_ACE
|
||||
- PDMA_FROM_ACE
|
||||
- PDMA_MEM_TO_MEM
|
||||
|
||||
@param channel_cfg
|
||||
The channel_cfg parameter specifies the configuration of the PDMA channel.
|
||||
The configuration includes:
|
||||
- channel priority
|
||||
- transfer size
|
||||
- source and/or destination address increment
|
||||
The channel_cfg parameter value is a logical OR of:
|
||||
One of the following to specify the channel priority:
|
||||
- PDMA_LOW_PRIORITY
|
||||
- PDMA_HIGH_PRIORITY
|
||||
One of the following to specify the transfer size:
|
||||
- PDMA_BYTE_TRANSFER
|
||||
- PDMA_HALFWORD_TRANSFER
|
||||
- PDMA_WORD_TRANSFER
|
||||
One or two of the following to specify the source and/or destination address
|
||||
increment:
|
||||
- PDMA_NO_INC
|
||||
- PDMA_INC_SRC_ONE_BYTE
|
||||
- PDMA_INC_SRC_TWO_BYTES
|
||||
- PDMA_INC_SRC_FOUR_BYTES
|
||||
- PDMA_INC_DEST_ONE_BYTE
|
||||
- PDMA_INC_DEST_TWO_BYTES
|
||||
- PDMA_INC_DEST_FOUR_BYTES
|
||||
|
||||
@param write_adjust
|
||||
The write_adjust parameter specifies the number of Cortex-M3 clock cycles
|
||||
the PDMA controller will wait before attempting another transfer cycle. This
|
||||
delay is necessary when peripherals are used as destination of a DMA transfer
|
||||
to ensure the DMA controller interprets the state of the peripheral’s ready
|
||||
signal only after data has actually been written to the peripheral. This delay
|
||||
accounts for posted writes (dump and run) for write accesses to peripherals.
|
||||
The effect of posted writes is that if the PDMA performs a write operation to
|
||||
a peripheral, the data is not actually written into the peripheral until
|
||||
sometime after the PDMA controller thinks it is written.
|
||||
A suitable value for write_adjust depends on the target of the DMA transfer.
|
||||
Guidelines for choosing this value are as follows:
|
||||
• The PDMA_DEFAULT_WRITE_ADJ constant provides a suitable default value
|
||||
for the write_adjust parameter when the PDMA channel is configured for
|
||||
transfers with MSS peripherals.
|
||||
• The PDMA_DEFAULT_WRITE_ADJ constant can also be used for DMA transfers
|
||||
with FPGA fabric implemented peripherals making use of the DMAREADY0 or
|
||||
DMAREADY1fabric interface signal to indicate that the peripheral is
|
||||
ready for another DMA transfer.
|
||||
• The write_adjust parameter can be set to zero to achieve maximum transfer
|
||||
speed for genuine memory to memory transfers.
|
||||
• The internal latency of FPGA implemented peripherals will decide the
|
||||
write_adjust value for fabric peripherals that do not use the DMAREADY0
|
||||
or DMAREADY1 fabric interface signals. You need to check the fabric
|
||||
peripheral documentation for the value to use.
|
||||
|
||||
Example:
|
||||
@code
|
||||
PDMA_configure
|
||||
(
|
||||
PDMA_CHANNEL_0,
|
||||
PDMA_TO_SPI_1,
|
||||
PDMA_LOW_PRIORITY | PDMA_BYTE_TRANSFER | PDMA_INC_SRC_ONE_BYTE,
|
||||
PDMA_DEFAULT_WRITE_ADJ
|
||||
);
|
||||
@endcode
|
||||
*/
|
||||
void PDMA_configure
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
pdma_src_dest_t src_dest,
|
||||
uint32_t channel_cfg,
|
||||
uint8_t write_adjust
|
||||
);
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_set_priority_ratio() function sets the ratio of high priority to low
|
||||
priority DMA access opportunities. This ratio is used by the PDMA controller
|
||||
arbiter to decide which PDMA channel will be given the opportunity to perform
|
||||
a transfer when multiple PDMA channels are requesting to transfer data at the
|
||||
same time. The priority ratio specifies how many DMA transfer opportunities
|
||||
will be given to high priority channels before a DMA transfer opportunity is
|
||||
given to a low priority channel when there are continuous requests from high
|
||||
priority channels.
|
||||
|
||||
@param priority_ratio
|
||||
The priority_ratio parameter specifies the ratio of DMA access opportunities
|
||||
given to high priority channels versus low priority channels.
|
||||
Allowed values for this parameter are:
|
||||
- PDMA_ROUND_ROBIN
|
||||
- PDMA_RATIO_HIGH_LOW_1_TO_1
|
||||
- PDMA_RATIO_HIGH_LOW_3_TO_1
|
||||
- PDMA_RATIO_HIGH_LOW_7_TO_1
|
||||
- PDMA_RATIO_HIGH_LOW_15_TO_1
|
||||
- PDMA_RATIO_HIGH_LOW_31_TO_1
|
||||
- PDMA_RATIO_HIGH_LOW_63_TO_1
|
||||
- PDMA_RATIO_HIGH_LOW_127_TO_1
|
||||
- PDMA_RATIO_HIGH_LOW_255_TO_1
|
||||
|
||||
Example:
|
||||
@code
|
||||
PDMA_set_priority_ratio( PDMA_ROUND_ROBIN );
|
||||
@endcode
|
||||
*/
|
||||
static __INLINE void PDMA_set_priority_ratio
|
||||
(
|
||||
pdma_priority_ratio_t priority_ratio
|
||||
)
|
||||
{
|
||||
PDMA->RATIO_HIGH_LOW = (uint32_t)priority_ratio;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_start() function initiates a DMA transfer. It specifies the source
|
||||
and destination address of the transfer as well as the number of transfers
|
||||
that must take place. The source and destination addresses can be the address
|
||||
of peripheral registers.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
|
||||
@param src_addr
|
||||
The src_addr parameter specifies the address location of the data to be
|
||||
transferred. You must ensure that this source address is consistent with the
|
||||
DMA source configured for the selected channel using the PDMA_configure()
|
||||
function.
|
||||
For DMA transfers from MSS peripheral to memory, the following src_addr
|
||||
parameter values are allowed:
|
||||
• PDMA_SPI0_RX_REGISTER
|
||||
• PDMA_SPI1_RX_REGISTER
|
||||
• PDMA_UART0_RX_REGISTER
|
||||
• PDMA_UART1_RX_REGISTER
|
||||
• PDMA_ACE_PPE_DATAOUT
|
||||
For DMA transfers from FPGA fabric peripheral to memory, the following
|
||||
src_addr parameter values are allowed:
|
||||
• An address in the FPGA fabric address space (0x40050000-0x400FFFFF)
|
||||
For DMA transfers from memory to MSS peripheral, or from memory to FPGA
|
||||
fabric peripheral, or from memory to memory, the following src_addr
|
||||
parameter values are allowed:
|
||||
• Any memory mapped address.
|
||||
|
||||
@param dest_addr
|
||||
The dest_addr parameter specifies the destination address of the PDMA
|
||||
transfer. You must ensure that this matches with the DMA destination
|
||||
configured for the selected channel.
|
||||
For DMA transfers from memory to MSS peripheral, the following dest_addr parameter values are allowed:
|
||||
• PDMA_SPI0_TX_REGISTER
|
||||
• PDMA_SPI1_TX_REGISTER
|
||||
• PDMA_UART0_TX_REGISTER
|
||||
• PDMA_UART1_TX_REGISTER
|
||||
• PDMA_ACE_SSE_DATAIN
|
||||
For DMA transfers from memory to FPGA fabric peripheral, the following
|
||||
dest_addr parameter values are allowed:
|
||||
• An address in the FPGA fabric address space (0x40050000-0x400FFFFF)
|
||||
For DMA transfers from MSS peripheral to memory, or from FPGA fabric
|
||||
peripheral to memory, or from memory to memory, the following dest_addr
|
||||
parameter values are allowed:
|
||||
• Any memory mapped address.
|
||||
|
||||
@param transfer_count
|
||||
The transfer_count parameter specifies the number of transfers to be
|
||||
performed. It is the number of bytes to transfer if the PDMA channel is
|
||||
configured for byte transfer, the number of half-words to transfer if the
|
||||
PDMA channel is configured for half-word transfer, or the number of words
|
||||
to transfer if the PDMA channel is configured for word transfer.
|
||||
|
||||
Example:
|
||||
@code
|
||||
PDMA_start
|
||||
(
|
||||
PDMA_CHANNEL_3,
|
||||
PDMA_SPI1_RX_REGISTER,
|
||||
(uint32_t)slave_rx_buffer,
|
||||
sizeof(slave_rx_buffer)
|
||||
);
|
||||
@endcode
|
||||
*/
|
||||
void PDMA_start
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
uint32_t src_addr,
|
||||
uint32_t dest_addr,
|
||||
uint16_t transfer_count
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_load_next_buffer() function sets the next buffer to be transferred.
|
||||
This function is called after a transfer has been initiated using the
|
||||
PDMA_start() function. Its purpose is to keep feeding a PDMA channel with data
|
||||
buffers.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
|
||||
@param src_addr
|
||||
The src_addr parameter specifies the address location of the data to be
|
||||
transferred. You must ensure that this source address is consistent with the
|
||||
DMA source configured for the selected channel using the PDMA_configure()
|
||||
function.
|
||||
For DMA transfers from MSS peripheral to memory, the following src_addr parameter values are allowed:
|
||||
• PDMA_SPI0_RX_REGISTER
|
||||
• PDMA_SPI1_RX_REGISTER
|
||||
• PDMA_UART0_RX_REGISTER
|
||||
• PDMA_UART1_RX_REGISTER
|
||||
• PDMA_ACE_PPE_DATAOUT
|
||||
For DMA transfers from FPGA fabric peripheral to memory, the following src_addr parameter values are allowed:
|
||||
• An address in the FPGA fabric address space (0x40050000-0x400FFFFF)
|
||||
For DMA transfers from memory to MSS peripheral, or from memory to FPGA fabric peripheral, or from memory to memory, the following src_addr parameter values are allowed:
|
||||
• Any memory mapped address.
|
||||
|
||||
@param dest_addr
|
||||
The dest_addr parameter specifies the destination address of the PDMA
|
||||
transfer. You must ensure that this matches with the DMA destination
|
||||
configured for the selected channel.
|
||||
For DMA transfers from memory to MSS peripheral, the following dest_addr parameter values are allowed:
|
||||
• PDMA_SPI0_TX_REGISTER
|
||||
• PDMA_SPI1_TX_REGISTER
|
||||
• PDMA_UART0_TX_REGISTER
|
||||
• PDMA_UART1_TX_REGISTER
|
||||
• PDMA_ACE_SSE_DATAIN
|
||||
For DMA transfers from memory to FPGA fabric peripheral, the following dest_addr parameter values are allowed:
|
||||
• An address in the FPGA fabric address space (0x40050000-0x400FFFFF)
|
||||
For DMA transfers from MSS peripheral to memory, or from FPGA fabric peripheral to memory, or from memory to memory, the following dest_addr parameter values are allowed:
|
||||
• Any memory mapped address.
|
||||
|
||||
@param transfer_count
|
||||
The transfer_count parameter specifies the number of transfers to be
|
||||
performed. It is the number of bytes to transfer if the PDMA channel is
|
||||
configured for byte transfer, the number of half-words to transfer if the
|
||||
PDMA channel is configured for half-word transfer or the number of words to
|
||||
transfer if the PDMA channel is configured for word transfer.
|
||||
|
||||
Example:
|
||||
@code
|
||||
void write_cmd_data
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
const uint8_t * cmd_buffer,
|
||||
uint16_t cmd_byte_size,
|
||||
uint8_t * data_buffer,
|
||||
uint16_t data_byte_size
|
||||
)
|
||||
{
|
||||
uint32_t transfer_size;
|
||||
|
||||
transfer_size = cmd_byte_size + data_byte_size;
|
||||
|
||||
MSS_SPI_disable( this_spi );
|
||||
MSS_SPI_set_transfer_byte_count( this_spi, transfer_size );
|
||||
|
||||
PDMA_start
|
||||
(
|
||||
PDMA_CHANNEL_0,
|
||||
(uint32_t)cmd_buffer,
|
||||
PDMA_SPI1_TX_REGISTER,
|
||||
cmd_byte_size
|
||||
);
|
||||
|
||||
PDMA_load_next_buffer
|
||||
(
|
||||
PDMA_CHANNEL_0,
|
||||
(uint32_t)data_buffer,
|
||||
PDMA_SPI1_TX_REGISTER,
|
||||
data_byte_size
|
||||
);
|
||||
|
||||
MSS_SPI_enable( this_spi );
|
||||
|
||||
while ( !MSS_SPI_tx_done(this_spi) )
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
void PDMA_load_next_buffer
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
uint32_t src_addr,
|
||||
uint32_t dest_addr,
|
||||
uint16_t transfer_count
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_status() function returns the status of a DMA channel.
|
||||
The returned value indicates if transfers have been completed using buffer A
|
||||
or buffer B of the PDMA hardware block.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
|
||||
@return
|
||||
bit 0 of the return value indicates if buffer A has been trasnfered. It is
|
||||
set to 1 if the transfer has completed.
|
||||
bit 1 of the return value indicates if buffer B has been transfered. It is
|
||||
set to 1 if the transfer has completed.
|
||||
*/
|
||||
uint32_t PDMA_status
|
||||
(
|
||||
pdma_channel_id_t channel_id
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_pause() function temporarily pauses a PDMA transfer taking place on
|
||||
the specified PDMA channel. The transfer can later be resumed by using the
|
||||
PDMA_resume() function.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
*/
|
||||
static __INLINE void PDMA_pause( pdma_channel_id_t channel_id )
|
||||
{
|
||||
PDMA->CHANNEL[channel_id].CRTL |= PDMA_PAUSE_MASK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_resume() function resumes a transfer previously paused using the
|
||||
PDMA_pause() function.
|
||||
|
||||
@param channel_id The channel_id parameter identifies the PDMA channel
|
||||
used by the function.
|
||||
*/
|
||||
static __INLINE void PDMA_resume( pdma_channel_id_t channel_id )
|
||||
{
|
||||
PDMA->CHANNEL[channel_id].CRTL &= ~PDMA_PAUSE_MASK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_enable_irq() enables the PDMA hardware to generate an interrupt when
|
||||
a DMA transfer completes on the specified PDMA channel. This function also
|
||||
enables the PDMA interrupt in the Cortex-M3 interrupt controller.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
*/
|
||||
void PDMA_enable_irq( pdma_channel_id_t channel_id );
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_disable_irq() disables interrupts for a specific PDMA channel.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
*/
|
||||
static __INLINE void PDMA_disable_irq( pdma_channel_id_t channel_id )
|
||||
{
|
||||
PDMA->CHANNEL[channel_id].CRTL &= ~PDMA_IRQ_ENABLE_MASK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_set_irq_handler() function registers a handler function for
|
||||
interrupts generated on the completion of a transfer on a specific PDMA
|
||||
channel. This function also enables the PDMA interrupt both in the PDMA
|
||||
controller and in the Cortex-M3 interrupt controller.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
|
||||
@param handler
|
||||
The handler parameter is a pointer to the function that will be called when
|
||||
a transfer completes on the PDMA channel identified by channel_id and the
|
||||
interrupt is enabled for that channel.
|
||||
|
||||
Example:
|
||||
@code
|
||||
void slave_dma_irq_handler( void )
|
||||
{
|
||||
if ( g_spi1_rx_buffer[2] == 0x99 )
|
||||
{
|
||||
PDMA_load_next_buffer
|
||||
(
|
||||
PDMA_CHANNEL_0,
|
||||
(uint32_t)g_spi1_tx_buffer_b,
|
||||
PDMA_SPI1_TX_REGISTER,
|
||||
sizeof(g_spi1_tx_buffer_b)
|
||||
);
|
||||
}
|
||||
PDMA_disable_irq( PDMA_CHANNEL_3 );
|
||||
}
|
||||
|
||||
void setup_dma( void )
|
||||
{
|
||||
PDMA_init();
|
||||
PDMA_configure
|
||||
(
|
||||
PDMA_CHANNEL_0,
|
||||
PDMA_TO_SPI_1,
|
||||
PDMA_LOW_PRIORITY | PDMA_BYTE_TRANSFER | PDMA_INC_SRC_ONE_BYTE
|
||||
);
|
||||
PDMA_configure
|
||||
(
|
||||
PDMA_CHANNEL_3,
|
||||
PDMA_FROM_SPI_1,
|
||||
PDMA_HIGH_PRIORITY | PDMA_BYTE_TRANSFER | PDMA_INC_DEST_ONE_BYTE
|
||||
);
|
||||
PDMA_set_irq_handler( PDMA_CHANNEL_3, slave_dma_irq_handler );
|
||||
PDMA_start( PDMA_CHANNEL_3, PDMA_SPI1_RX_REGISTER, (uint32_t)g_spi1_rx_buffer, 3 );
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
void PDMA_set_irq_handler
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
pdma_channel_isr_t handler
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_clear_irq() function clears interrupts for a specific PDMA channel.
|
||||
This function also clears the PDMA interrupt in the Cortex-M3 NVIC.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
*/
|
||||
void PDMA_clear_irq
|
||||
(
|
||||
pdma_channel_id_t channel_id
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MSS_PERIPHERAL_DMA_H_ */
|
|
@ -1,610 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2008 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion microcontroller subsystem SPI bare metal software driver
|
||||
* implementation.
|
||||
*
|
||||
* SVN $Revision: 2176 $
|
||||
* SVN $Date: 2010-02-15 21:04:22 +0000 (Mon, 15 Feb 2010) $
|
||||
*/
|
||||
#include "mss_spi.h"
|
||||
#include "../../CMSIS/mss_assert.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
MSS SPI can operate as master or slave.
|
||||
*/
|
||||
#define MSS_SPI_MODE_SLAVE (uint32_t)0
|
||||
#define MSS_SPI_MODE_MASTER (uint32_t)1
|
||||
|
||||
/***************************************************************************//**
|
||||
* Mask of transfer protocol and SPO, SPH bits within control register.
|
||||
*/
|
||||
#define PROTOCOL_MODE_MASK (uint32_t)0x030000C0
|
||||
|
||||
/***************************************************************************//**
|
||||
* Mask of theframe count bits within the SPI control register.
|
||||
*/
|
||||
#define TXRXDFCOUNT_MASK (uint32_t)0x00FFFF00
|
||||
#define TXRXDFCOUNT_SHIFT (uint32_t)8
|
||||
|
||||
/***************************************************************************//**
|
||||
* SPI hardware FIFO depth.
|
||||
*/
|
||||
#define RX_FIFO_SIZE 4u
|
||||
|
||||
/***************************************************************************//**
|
||||
Marker used to detect that the configuration has not been selected for a
|
||||
specific slave when operating as a master.
|
||||
*/
|
||||
#define NOT_CONFIGURED 0xFFFFFFFF
|
||||
|
||||
/***************************************************************************//**
|
||||
* SPI instance data structures for SPI0 and SPI1. A pointer to these data
|
||||
* structures must be used as first parameter to any of the SPI driver functions
|
||||
* to identify the SPI hardware block that will perform the requested operation.
|
||||
*/
|
||||
mss_spi_instance_t g_mss_spi0;
|
||||
mss_spi_instance_t g_mss_spi1;
|
||||
|
||||
/***************************************************************************//**
|
||||
SPI0 interrupt service routine
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void SPI0_IRQHandler( void );
|
||||
#else
|
||||
void SPI0_IRQHandler( void );
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
SPI1 interrupt service routine
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void SPI1_IRQHandler( void );
|
||||
#else
|
||||
void SPI1_IRQHandler( void );
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_init()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_init
|
||||
(
|
||||
mss_spi_instance_t * this_spi
|
||||
)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
if (this_spi == &g_mss_spi0)
|
||||
{
|
||||
this_spi->hw_reg = SPI0;
|
||||
this_spi->hw_reg_bit = SPI0_BITBAND;
|
||||
this_spi->irqn = SPI0_IRQn;
|
||||
|
||||
/* reset SPI0 */
|
||||
SYSREG->SOFT_RST_CR |= SYSREG_SPI0_SOFTRESET_MASK;
|
||||
/* Clear any previously pended SPI0 interrupt */
|
||||
NVIC_ClearPendingIRQ( SPI0_IRQn );
|
||||
/* Take SPI0 out of reset. */
|
||||
SYSREG->SOFT_RST_CR &= ~SYSREG_SPI0_SOFTRESET_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
this_spi->hw_reg = SPI1;
|
||||
this_spi->hw_reg_bit = SPI1_BITBAND;
|
||||
this_spi->irqn = SPI1_IRQn;
|
||||
|
||||
/* reset SPI1 */
|
||||
SYSREG->SOFT_RST_CR |= SYSREG_SPI1_SOFTRESET_MASK;
|
||||
/* Clear any previously pended SPI1 interrupt */
|
||||
NVIC_ClearPendingIRQ( SPI1_IRQn );
|
||||
/* Take SPI1 out of reset. */
|
||||
SYSREG->SOFT_RST_CR &= ~SYSREG_SPI1_SOFTRESET_MASK;
|
||||
}
|
||||
|
||||
this_spi->frame_rx_handler = 0U;
|
||||
this_spi->slave_tx_frame = 0U;
|
||||
|
||||
this_spi->block_rx_handler = 0U;
|
||||
|
||||
this_spi->slave_tx_buffer = 0U;
|
||||
this_spi->slave_tx_size = 0U;
|
||||
this_spi->slave_tx_idx = 0U;
|
||||
|
||||
for ( i = 0u; i < (uint16_t)MSS_SPI_MAX_NB_OF_SLAVES; ++i )
|
||||
{
|
||||
this_spi->slaves_cfg[i].ctrl_reg = NOT_CONFIGURED;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_configure_slave_mode()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_configure_slave_mode
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
mss_spi_protocol_mode_t protocol_mode,
|
||||
mss_spi_pclk_div_t clk_rate,
|
||||
uint8_t frame_bit_length
|
||||
)
|
||||
{
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
ASSERT( frame_bit_length <= 32 );
|
||||
|
||||
/* Set the mode. */
|
||||
this_spi->hw_reg_bit->CTRL_MASTER = MSS_SPI_MODE_SLAVE;
|
||||
|
||||
/* Set the clock rate. */
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 0U;
|
||||
this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~PROTOCOL_MODE_MASK) | (uint32_t)protocol_mode;
|
||||
this_spi->hw_reg->CLK_GEN = (uint32_t)clk_rate;
|
||||
|
||||
/* Set default frame size to byte size and number of data frames to 1. */
|
||||
this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | ((uint32_t)1 << TXRXDFCOUNT_SHIFT);
|
||||
this_spi->hw_reg->TXRXDF_SIZE = frame_bit_length;
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 1U;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_configure_master_mode()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_configure_master_mode
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
mss_spi_slave_t slave,
|
||||
mss_spi_protocol_mode_t protocol_mode,
|
||||
mss_spi_pclk_div_t clk_rate,
|
||||
uint8_t frame_bit_length
|
||||
)
|
||||
{
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
ASSERT( slave < MSS_SPI_MAX_NB_OF_SLAVES );
|
||||
ASSERT( frame_bit_length <= 32 );
|
||||
|
||||
/* Set the mode. */
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 0U;
|
||||
this_spi->hw_reg_bit->CTRL_MASTER = MSS_SPI_MODE_MASTER;
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 1U;
|
||||
|
||||
/*
|
||||
* Keep track of the required register configuration for this slave. These
|
||||
* values will be used by the MSS_SPI_set_slave_select() function to configure
|
||||
* the master to match the slave being selected.
|
||||
*/
|
||||
if ( slave < MSS_SPI_MAX_NB_OF_SLAVES )
|
||||
{
|
||||
this_spi->slaves_cfg[slave].ctrl_reg = 0x00000002uL | (uint32_t)protocol_mode | ((uint32_t)1 << TXRXDFCOUNT_SHIFT);
|
||||
this_spi->slaves_cfg[slave].txrxdf_size_reg = frame_bit_length;
|
||||
this_spi->slaves_cfg[slave].clk_gen = (uint8_t)clk_rate;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_set_slave_select()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_set_slave_select
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
mss_spi_slave_t slave
|
||||
)
|
||||
{
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
/* This function is only intended to be used with an SPI master. */
|
||||
ASSERT( this_spi->hw_reg_bit->CTRL_MASTER == MSS_SPI_MODE_MASTER );
|
||||
ASSERT( this_spi->slaves_cfg[slave].ctrl_reg != NOT_CONFIGURED );
|
||||
|
||||
/* Set the clock rate. */
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 0U;
|
||||
this_spi->hw_reg->CONTROL = this_spi->slaves_cfg[slave].ctrl_reg;
|
||||
this_spi->hw_reg->CLK_GEN = this_spi->slaves_cfg[slave].clk_gen;
|
||||
this_spi->hw_reg->TXRXDF_SIZE = this_spi->slaves_cfg[slave].txrxdf_size_reg;
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 1U;
|
||||
|
||||
/* Set slave select */
|
||||
this_spi->hw_reg->SLAVE_SELECT |= ((uint32_t)1 << (uint32_t)slave);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_clear_slave_select()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_clear_slave_select
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
mss_spi_slave_t slave
|
||||
)
|
||||
{
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
/* This function is only intended to be used with an SPI master. */
|
||||
ASSERT( this_spi->hw_reg_bit->CTRL_MASTER == MSS_SPI_MODE_MASTER );
|
||||
|
||||
this_spi->hw_reg->SLAVE_SELECT &= ~((uint32_t)1 << (uint32_t)slave);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_transfer_frame()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
uint32_t MSS_SPI_transfer_frame
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
uint32_t tx_bits
|
||||
)
|
||||
{
|
||||
volatile uint32_t dummy;
|
||||
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
/* This function is only intended to be used with an SPI master. */
|
||||
ASSERT( this_spi->hw_reg_bit->CTRL_MASTER == MSS_SPI_MODE_MASTER );
|
||||
|
||||
/* Flush Rx FIFO. */
|
||||
while ( this_spi->hw_reg_bit->STATUS_RX_RDY == 1U )
|
||||
{
|
||||
dummy = this_spi->hw_reg->RX_DATA;
|
||||
dummy = dummy; /* Prevent Lint warning. */
|
||||
}
|
||||
|
||||
/* Send frame. */
|
||||
this_spi->hw_reg->TX_DATA = tx_bits;
|
||||
|
||||
/* Wait for frame Tx to complete. */
|
||||
while ( this_spi->hw_reg_bit->STATUS_TX_DONE == 0U )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
/* Read received frame. */
|
||||
/* Wait for Rx complete. */
|
||||
while ( this_spi->hw_reg_bit->STATUS_RX_RDY == 0U )
|
||||
{
|
||||
;
|
||||
}
|
||||
/* Return Rx data. */
|
||||
return( this_spi->hw_reg->RX_DATA );
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_transfer_block()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_transfer_block
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
const uint8_t * cmd_buffer,
|
||||
uint16_t cmd_byte_size,
|
||||
uint8_t * rd_buffer,
|
||||
uint16_t rd_byte_size
|
||||
)
|
||||
{
|
||||
uint16_t transfer_idx = 0U;
|
||||
uint16_t tx_idx;
|
||||
uint16_t rx_idx;
|
||||
uint32_t frame_count;
|
||||
volatile uint32_t rx_raw;
|
||||
uint16_t transit = 0U;
|
||||
|
||||
uint16_t transfer_size; /* Total number of bytes transfered. */
|
||||
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
/* This function is only intended to be used with an SPI master. */
|
||||
ASSERT( this_spi->hw_reg_bit->CTRL_MASTER == MSS_SPI_MODE_MASTER );
|
||||
|
||||
/* Compute number of bytes to transfer. */
|
||||
transfer_size = cmd_byte_size + rd_byte_size;
|
||||
|
||||
/* Adjust to 1 byte transfer to cater for DMA transfers. */
|
||||
if ( transfer_size == 0U )
|
||||
{
|
||||
frame_count = 1U;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame_count = transfer_size;
|
||||
}
|
||||
|
||||
/* Set frame size to 8 bits and the frame count to the tansfer size. */
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 0U;
|
||||
this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | ( (frame_count << TXRXDFCOUNT_SHIFT) & TXRXDFCOUNT_MASK);
|
||||
this_spi->hw_reg->TXRXDF_SIZE = 8U;
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 1U;
|
||||
|
||||
/* Flush the receive FIFO. */
|
||||
while ( !this_spi->hw_reg_bit->STATUS_RX_FIFO_EMPTY )
|
||||
{
|
||||
rx_raw = this_spi->hw_reg->RX_DATA;
|
||||
}
|
||||
|
||||
tx_idx = 0u;
|
||||
rx_idx = 0u;
|
||||
if ( tx_idx < cmd_byte_size )
|
||||
{
|
||||
this_spi->hw_reg->TX_DATA = cmd_buffer[tx_idx];
|
||||
++tx_idx;
|
||||
++transit;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( tx_idx < transfer_size )
|
||||
{
|
||||
this_spi->hw_reg->TX_DATA = 0x00U;
|
||||
++tx_idx;
|
||||
++transit;
|
||||
}
|
||||
}
|
||||
/* Perform the remainder of the transfer by sending a byte every time a byte
|
||||
* has been received. This should ensure that no Rx overflow can happen in
|
||||
* case of an interrupt occurs during this function. */
|
||||
while ( transfer_idx < transfer_size )
|
||||
{
|
||||
if ( !this_spi->hw_reg_bit->STATUS_RX_FIFO_EMPTY )
|
||||
{
|
||||
/* Process received byte. */
|
||||
rx_raw = this_spi->hw_reg->RX_DATA;
|
||||
if ( transfer_idx >= cmd_byte_size )
|
||||
{
|
||||
if ( rx_idx < rd_byte_size )
|
||||
{
|
||||
rd_buffer[rx_idx] = (uint8_t)rx_raw;
|
||||
}
|
||||
++rx_idx;
|
||||
}
|
||||
++transfer_idx;
|
||||
--transit;
|
||||
}
|
||||
|
||||
if ( !this_spi->hw_reg_bit->STATUS_TX_FIFO_FULL )
|
||||
{
|
||||
if (transit < RX_FIFO_SIZE)
|
||||
{
|
||||
/* Send another byte. */
|
||||
if ( tx_idx < cmd_byte_size )
|
||||
{
|
||||
this_spi->hw_reg->TX_DATA = cmd_buffer[tx_idx];
|
||||
++tx_idx;
|
||||
++transit;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( tx_idx < transfer_size )
|
||||
{
|
||||
this_spi->hw_reg->TX_DATA = 0x00U;
|
||||
++tx_idx;
|
||||
++transit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_set_frame_rx_handler()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_set_frame_rx_handler
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
mss_spi_frame_rx_handler_t rx_handler
|
||||
)
|
||||
{
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
/* This function is only intended to be used with an SPI slave. */
|
||||
ASSERT( this_spi->hw_reg_bit->CTRL_MASTER == MSS_SPI_MODE_SLAVE );
|
||||
|
||||
/* Disable block Rx handler as they are mutually exclusive. */
|
||||
this_spi->block_rx_handler = 0U;
|
||||
|
||||
/* Keep a copy of the pointer to the rx hnadler function. */
|
||||
this_spi->frame_rx_handler = rx_handler;
|
||||
|
||||
/* Enable Rx interrupt. */
|
||||
this_spi->hw_reg_bit->CTRL_RX_INT_EN = 1U;
|
||||
NVIC_EnableIRQ( this_spi->irqn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_set_slave_tx_frame()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_set_slave_tx_frame
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
uint32_t frame_value
|
||||
)
|
||||
{
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
/* This function is only intended to be used with an SPI slave. */
|
||||
ASSERT( this_spi->hw_reg_bit->CTRL_MASTER == MSS_SPI_MODE_SLAVE );
|
||||
|
||||
/* Disable slave block tx buffer as it is mutually exclusive with frame
|
||||
* level handling. */
|
||||
this_spi->slave_tx_buffer = 0U;
|
||||
this_spi->slave_tx_size = 0U;
|
||||
this_spi->slave_tx_idx = 0U;
|
||||
|
||||
/* Keep a copy of the slave tx frame value. */
|
||||
this_spi->slave_tx_frame = frame_value;
|
||||
|
||||
/* Load frame into Tx data register. */
|
||||
this_spi->hw_reg->TX_DATA = this_spi->slave_tx_frame;
|
||||
|
||||
/* Enable Tx Done interrupt in order to reload the slave Tx frame after each
|
||||
* time it has been sent. */
|
||||
this_spi->hw_reg_bit->CTRL_TX_INT_EN = 1U;
|
||||
NVIC_EnableIRQ( this_spi->irqn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_set_slave_block_buffers()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_set_slave_block_buffers
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
const uint8_t * tx_buffer,
|
||||
uint32_t tx_buff_size,
|
||||
uint8_t * rx_buffer,
|
||||
uint32_t rx_buff_size,
|
||||
mss_spi_block_rx_handler_t block_rx_handler
|
||||
)
|
||||
{
|
||||
uint32_t frame_count;
|
||||
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
/* This function is only intended to be used with an SPI slave. */
|
||||
ASSERT( this_spi->hw_reg_bit->CTRL_MASTER == MSS_SPI_MODE_SLAVE );
|
||||
|
||||
/* Disable Rx frame handler as it is mutually exclusive with block rx handler. */
|
||||
this_spi->frame_rx_handler = 0U;
|
||||
|
||||
/* Keep a copy of the pointer to the block rx handler function. */
|
||||
this_spi->block_rx_handler = block_rx_handler;
|
||||
|
||||
this_spi->slave_rx_buffer = rx_buffer;
|
||||
this_spi->slave_rx_size = rx_buff_size;
|
||||
this_spi->slave_rx_idx = 0U;
|
||||
|
||||
/**/
|
||||
this_spi->slave_tx_buffer = tx_buffer;
|
||||
this_spi->slave_tx_size = tx_buff_size;
|
||||
this_spi->slave_tx_idx = 0U;
|
||||
|
||||
frame_count = rx_buff_size;
|
||||
|
||||
/**/
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 0U;
|
||||
this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | (frame_count << TXRXDFCOUNT_SHIFT);
|
||||
this_spi->hw_reg->TXRXDF_SIZE = 8U;
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 1U;
|
||||
|
||||
/* Load the transmit FIFO. */
|
||||
while ( !(this_spi->hw_reg_bit->STATUS_TX_FIFO_FULL) && ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) )
|
||||
{
|
||||
this_spi->hw_reg->TX_DATA = this_spi->slave_tx_buffer[this_spi->slave_tx_idx];
|
||||
++this_spi->slave_tx_idx;
|
||||
}
|
||||
|
||||
/* Enable Rx interrupt. */
|
||||
this_spi->hw_reg_bit->CTRL_RX_INT_EN = 1U;
|
||||
NVIC_EnableIRQ( this_spi->irqn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* SPI interrupt service routine.
|
||||
*/
|
||||
static void mss_spi_isr
|
||||
(
|
||||
mss_spi_instance_t * this_spi
|
||||
)
|
||||
{
|
||||
uint32_t rx_frame;
|
||||
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
if ( this_spi->hw_reg_bit->MIS_RX_RDY )
|
||||
{
|
||||
while( !this_spi->hw_reg_bit->STATUS_RX_FIFO_EMPTY )
|
||||
{
|
||||
rx_frame = this_spi->hw_reg->RX_DATA;
|
||||
if ( this_spi->frame_rx_handler != 0U )
|
||||
{
|
||||
/* Single frame handling mode. */
|
||||
this_spi->frame_rx_handler( rx_frame );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( this_spi->block_rx_handler != 0U )
|
||||
{
|
||||
/* Block handling mode. */
|
||||
if ( this_spi->slave_rx_idx < this_spi->slave_rx_size )
|
||||
{
|
||||
this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame;
|
||||
++this_spi->slave_rx_idx;
|
||||
if ( this_spi->slave_rx_idx == this_spi->slave_rx_size )
|
||||
{
|
||||
(*this_spi->block_rx_handler)( this_spi->slave_rx_buffer, this_spi->slave_rx_size );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Feed transmit FIFO. */
|
||||
if ( !(this_spi->hw_reg_bit->STATUS_TX_FIFO_FULL) && ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) )
|
||||
{
|
||||
this_spi->hw_reg->TX_DATA = this_spi->slave_tx_buffer[this_spi->slave_tx_idx];
|
||||
++this_spi->slave_tx_idx;
|
||||
}
|
||||
}
|
||||
this_spi->hw_reg_bit->INT_CLEAR_RX_RDY = 1U;
|
||||
}
|
||||
|
||||
if ( this_spi->hw_reg_bit->MIS_TX_DONE )
|
||||
{
|
||||
if ( this_spi->slave_tx_buffer != 0U )
|
||||
{
|
||||
this_spi->hw_reg->TX_DATA = this_spi->slave_tx_buffer[this_spi->slave_tx_idx];
|
||||
++this_spi->slave_tx_idx;
|
||||
if ( this_spi->slave_tx_idx >= this_spi->slave_tx_size )
|
||||
{
|
||||
this_spi->slave_tx_idx = 0U;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reload slave tx frame into Tx data register. */
|
||||
this_spi->hw_reg->TX_DATA = this_spi->slave_tx_frame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* SPIO interrupt service routine.
|
||||
* Please note that the name of this ISR is defined as part of the SmartFusion
|
||||
* CMSIS startup code.
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void SPI0_IRQHandler( void )
|
||||
#else
|
||||
void SPI0_IRQHandler( void )
|
||||
#endif
|
||||
{
|
||||
mss_spi_isr( &g_mss_spi0 );
|
||||
NVIC_ClearPendingIRQ( SPI0_IRQn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* SPI1 interrupt service routine.
|
||||
* Please note that the name of this ISR is defined as part of the SmartFusion
|
||||
* CMSIS startup code.
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void SPI1_IRQHandler( void )
|
||||
#else
|
||||
void SPI1_IRQHandler( void )
|
||||
#endif
|
||||
{
|
||||
mss_spi_isr( &g_mss_spi1 );
|
||||
NVIC_ClearPendingIRQ( SPI1_IRQn );
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,458 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2007 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion Microcontroller Subsystem UART bare metal software driver
|
||||
* implementation.
|
||||
*
|
||||
* SVN $Revision: 1898 $
|
||||
* SVN $Date: 2009-12-21 17:27:57 +0000 (Mon, 21 Dec 2009) $
|
||||
*/
|
||||
#include "mss_uart.h"
|
||||
#include "../../CMSIS/mss_assert.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* defines
|
||||
*/
|
||||
#define TX_READY 0x01U
|
||||
#define TX_COMPLETE 0U
|
||||
|
||||
#define TX_FIFO_SIZE 16U
|
||||
|
||||
#define FCR_TRIG_LEVEL_MASK 0xC0U
|
||||
|
||||
#define IIRF_MASK 0x0FU
|
||||
|
||||
/*******************************************************************************
|
||||
* Possible values for Interrupt Identification Register Field.
|
||||
*/
|
||||
#define IIRF_MODEM_STATUS 0x00U
|
||||
#define IIRF_THRE 0x02U
|
||||
#define IIRF_RX_DATA 0x04U
|
||||
#define IIRF_RX_LINE_STATUS 0x06U
|
||||
#define IIRF_DATA_TIMEOUT 0x0CU
|
||||
|
||||
/*******************************************************************************
|
||||
* Cortex-M3 interrupt handler functions implemented as part of the MSS UART
|
||||
* driver.
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void UART0_IRQHandler( void );
|
||||
#else
|
||||
void UART0_IRQHandler( void );
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void UART1_IRQHandler( void );
|
||||
#else
|
||||
void UART1_IRQHandler( void );
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Local functions.
|
||||
*/
|
||||
static void MSS_UART_isr( mss_uart_instance_t * this_uart );
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
*/
|
||||
mss_uart_instance_t g_mss_uart0;
|
||||
mss_uart_instance_t g_mss_uart1;
|
||||
|
||||
/***************************************************************************//**
|
||||
* UART_init.
|
||||
* Initialises the UART with default configuration.
|
||||
*/
|
||||
void
|
||||
MSS_UART_init
|
||||
(
|
||||
mss_uart_instance_t* this_uart,
|
||||
uint32_t baud_rate,
|
||||
uint8_t line_config
|
||||
)
|
||||
{
|
||||
uint16_t baud_value;
|
||||
uint32_t pclk_freq;
|
||||
|
||||
/* The driver expects g_mss_uart0 and g_mss_uart1 to be the only
|
||||
* mss_uart_instance_t instances used to identfy UART0 and UART1. */
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
/* Force the value of the CMSIS global variables holding the various system
|
||||
* clock frequencies to be updated. */
|
||||
SystemCoreClockUpdate();
|
||||
|
||||
if ( this_uart == &g_mss_uart0 )
|
||||
{
|
||||
this_uart->hw_reg = UART0;
|
||||
this_uart->hw_reg_bit = UART0_BITBAND;
|
||||
this_uart->irqn = UART0_IRQn;
|
||||
|
||||
pclk_freq = g_FrequencyPCLK0;
|
||||
|
||||
/* reset UART0 */
|
||||
SYSREG->SOFT_RST_CR |= SYSREG_UART0_SOFTRESET_MASK;
|
||||
/* Clear any previously pended UART0 interrupt */
|
||||
NVIC_ClearPendingIRQ( UART0_IRQn );
|
||||
/* Take UART0 out of reset. */
|
||||
SYSREG->SOFT_RST_CR &= ~SYSREG_UART0_SOFTRESET_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
this_uart->hw_reg = UART1;
|
||||
this_uart->hw_reg_bit = UART1_BITBAND;
|
||||
this_uart->irqn = UART1_IRQn;
|
||||
|
||||
pclk_freq = g_FrequencyPCLK1;
|
||||
|
||||
/* Reset UART1 */
|
||||
SYSREG->SOFT_RST_CR |= SYSREG_UART1_SOFTRESET_MASK;
|
||||
/* Clear any previously pended UART1 interrupt */
|
||||
NVIC_ClearPendingIRQ( UART1_IRQn );
|
||||
/* Take UART1 out of reset. */
|
||||
SYSREG->SOFT_RST_CR &= ~SYSREG_UART1_SOFTRESET_MASK;
|
||||
}
|
||||
|
||||
/* disable interrupts */
|
||||
this_uart->hw_reg->IER = 0U;
|
||||
|
||||
/*
|
||||
* Compute baud value based on requested baud rate and PCLK frequency.
|
||||
* The baud value is computed using the following equation:
|
||||
* baud_value = PCLK_Frequency / (baud_rate * 16)
|
||||
* The baud value is rounded up or down depending on what would be the remainder
|
||||
* of the divide by 16 operation.
|
||||
*/
|
||||
baud_value = (uint16_t)(pclk_freq / baud_rate);
|
||||
if ( baud_value & 0x00000008U )
|
||||
{
|
||||
/* remainder above 0.5 */
|
||||
baud_value = (baud_value >> 4U) + 1U;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* remainder below 0.5 */
|
||||
baud_value = (baud_value >> 4U);
|
||||
}
|
||||
|
||||
/* set divisor latch */
|
||||
this_uart->hw_reg_bit->LCR_DLAB = (uint32_t)1;
|
||||
|
||||
/* msb of baud value */
|
||||
this_uart->hw_reg->DMR = (uint8_t)(baud_value >> 8);
|
||||
/* lsb of baud value */
|
||||
this_uart->hw_reg->DLR = (uint8_t)baud_value;
|
||||
|
||||
/* reset divisor latch */
|
||||
this_uart->hw_reg_bit->LCR_DLAB = (uint32_t)0;
|
||||
|
||||
/* set the line control register (bit length, stop bits, parity) */
|
||||
this_uart->hw_reg->LCR = line_config;
|
||||
|
||||
/* FIFO configuration */
|
||||
this_uart->hw_reg->FCR = (uint8_t)MSS_UART_FIFO_SINGLE_BYTE;
|
||||
|
||||
/* disable loopback */
|
||||
this_uart->hw_reg_bit->MCR_LOOP = (uint32_t)0;
|
||||
|
||||
/* Instance setup */
|
||||
this_uart->tx_buff_size = TX_COMPLETE;
|
||||
this_uart->tx_buffer = (const uint8_t *)0;
|
||||
this_uart->tx_idx = 0U;
|
||||
|
||||
this_uart->rx_handler = (mss_uart_rx_handler_t)0;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_uart.h for details of how to use this function.
|
||||
*/
|
||||
void
|
||||
MSS_UART_polled_tx
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
const uint8_t * pbuff,
|
||||
uint32_t tx_size
|
||||
)
|
||||
{
|
||||
uint32_t char_idx;
|
||||
uint32_t status;
|
||||
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
for ( char_idx = 0U; char_idx < tx_size; char_idx++ )
|
||||
{
|
||||
/* Wait for UART to become ready to transmit. */
|
||||
do {
|
||||
status = this_uart->hw_reg_bit->LSR_THRE;
|
||||
} while ( (status & TX_READY) == 0U );
|
||||
/* Send next character in the buffer. */
|
||||
this_uart->hw_reg->THR = pbuff[char_idx];
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_uart.h for details of how to use this function.
|
||||
*/
|
||||
void
|
||||
MSS_UART_polled_tx_string
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
const uint8_t * p_sz_string
|
||||
)
|
||||
{
|
||||
uint32_t char_idx;
|
||||
uint32_t status;
|
||||
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
char_idx = 0U;
|
||||
|
||||
while ( p_sz_string[char_idx] != 0U )
|
||||
{
|
||||
/* Wait for UART to become ready to transmit. */
|
||||
do {
|
||||
status = this_uart->hw_reg_bit->LSR_THRE;
|
||||
} while ( (status & TX_READY) == 0U);
|
||||
/* Send next character in the buffer. */
|
||||
this_uart->hw_reg->THR = p_sz_string[char_idx];
|
||||
++char_idx;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_uart.h for details of how to use this function.
|
||||
*/
|
||||
void
|
||||
MSS_UART_irq_tx
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
const uint8_t * pbuff,
|
||||
uint32_t tx_size
|
||||
)
|
||||
{
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
if ( tx_size > 0U )
|
||||
{
|
||||
/*Initialise the transmit info for the UART instance with the arguments.*/
|
||||
this_uart->tx_buffer = pbuff;
|
||||
this_uart->tx_buff_size = tx_size;
|
||||
this_uart->tx_idx = (uint16_t)0;
|
||||
|
||||
/* enables TX interrupt */
|
||||
this_uart->hw_reg_bit->IER_ETBEI = (uint32_t)1;
|
||||
|
||||
/* Enable UART instance interrupt in Cortex-M3 NVIC. */
|
||||
NVIC_EnableIRQ( this_uart->irqn );
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_uart.h for details of how to use this function.
|
||||
*/
|
||||
int8_t
|
||||
MSS_UART_tx_complete
|
||||
(
|
||||
mss_uart_instance_t * this_uart
|
||||
)
|
||||
{
|
||||
int8_t ret_value = 0;
|
||||
uint32_t transmit_empty = this_uart->hw_reg_bit->LSR_TEMT;
|
||||
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
if ( ( TX_COMPLETE == this_uart->tx_buff_size ) && transmit_empty )
|
||||
{
|
||||
ret_value = 1;
|
||||
}
|
||||
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_uart.h for details of how to use this function.
|
||||
*/
|
||||
size_t
|
||||
MSS_UART_get_rx
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
uint8_t * rx_buff,
|
||||
size_t buff_size
|
||||
)
|
||||
{
|
||||
size_t rx_size = 0U;
|
||||
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
while (( this_uart->hw_reg_bit->LSR_DR != 0U) && ( rx_size < buff_size ) )
|
||||
{
|
||||
rx_buff[rx_size] = this_uart->hw_reg->RBR;
|
||||
++rx_size;
|
||||
}
|
||||
|
||||
return rx_size;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Interrupt service routine triggered by the Transmitter Holding Register
|
||||
* Empty (THRE) interrupt or Received Data Available (RDA).
|
||||
* On THRE irq this routine will transmit the data from the transmit buffer.
|
||||
* When all bytes are transmitted, this routine disables the THRE interrupt
|
||||
* and resets the transmit counter.
|
||||
* On RDA irq this routine will call the user's receive handler routine previously
|
||||
* registered with the UART driver through a call to UART_set_rx_handler().
|
||||
*/
|
||||
static void
|
||||
MSS_UART_isr
|
||||
(
|
||||
mss_uart_instance_t * this_uart
|
||||
)
|
||||
{
|
||||
uint8_t iirf;
|
||||
uint32_t tx_empty;
|
||||
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
iirf = this_uart->hw_reg->IIR & IIRF_MASK;
|
||||
|
||||
switch ( iirf )
|
||||
{
|
||||
case IIRF_MODEM_STATUS:
|
||||
break;
|
||||
|
||||
case IIRF_THRE: /* Transmitter Holding Register Empty */
|
||||
tx_empty = this_uart->hw_reg_bit->LSR_TEMT;
|
||||
|
||||
if ( tx_empty )
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t fill_size = TX_FIFO_SIZE;
|
||||
uint32_t tx_remain = this_uart->tx_buff_size - this_uart->tx_idx;
|
||||
if ( tx_remain < TX_FIFO_SIZE )
|
||||
{
|
||||
fill_size = tx_remain;
|
||||
}
|
||||
/* Fill up FIFO */
|
||||
for ( i = 0U; i < fill_size; ++i )
|
||||
{
|
||||
this_uart->hw_reg->THR = this_uart->tx_buffer[this_uart->tx_idx];
|
||||
++this_uart->tx_idx;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this_uart->hw_reg->THR = this_uart->tx_buffer[this_uart->tx_idx];
|
||||
++this_uart->tx_idx;
|
||||
}
|
||||
|
||||
if ( this_uart->tx_idx == this_uart->tx_buff_size )
|
||||
{
|
||||
this_uart->tx_buff_size = TX_COMPLETE;
|
||||
/* disables TX interrupt */
|
||||
this_uart->hw_reg_bit->IER_ETBEI = 0U;
|
||||
}
|
||||
break;
|
||||
|
||||
case IIRF_RX_DATA: /* Received Data Available */
|
||||
case IIRF_DATA_TIMEOUT:
|
||||
if (this_uart->rx_handler != 0)
|
||||
{
|
||||
(*(this_uart->rx_handler))();
|
||||
}
|
||||
break;
|
||||
|
||||
case IIRF_RX_LINE_STATUS:
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Disable other interrupts */
|
||||
this_uart->hw_reg_bit->IER_ELSI = 0U;
|
||||
this_uart->hw_reg_bit->IER_EDSSI = 0U;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_uart.h for details of how to use this function.
|
||||
*/
|
||||
void
|
||||
MSS_UART_set_rx_handler
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
mss_uart_rx_handler_t handler,
|
||||
mss_uart_rx_trig_level_t trigger_level
|
||||
)
|
||||
{
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
this_uart->rx_handler = handler;
|
||||
|
||||
/* Set the receive interrupt trigger level. */
|
||||
this_uart->hw_reg->FCR = (this_uart->hw_reg->FCR & (uint8_t)(~((uint8_t)FCR_TRIG_LEVEL_MASK))) | (uint8_t)trigger_level;
|
||||
|
||||
/* Enable receive interrupt. */
|
||||
this_uart->hw_reg_bit->IER_ERBFI = 1U;
|
||||
|
||||
/* Enable UART instance interrupt in Cortex-M3 NVIC. */
|
||||
NVIC_EnableIRQ( this_uart->irqn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_uart.h for details of how to use this function.
|
||||
*/
|
||||
void
|
||||
MSS_UART_set_loopback
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
mss_uart_loopback_t loopback
|
||||
)
|
||||
{
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
if ( loopback == MSS_UART_LOOPBACK_OFF )
|
||||
{
|
||||
this_uart->hw_reg_bit->MCR_LOOP = 0U;
|
||||
}
|
||||
else
|
||||
{
|
||||
this_uart->hw_reg_bit->MCR_LOOP = 1U;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* UART0 interrupt service routine.
|
||||
* UART0_IRQHandler is included within the Cortex-M3 vector table as part of the
|
||||
* Fusion 2 CMSIS.
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void UART0_IRQHandler( void )
|
||||
#else
|
||||
void UART0_IRQHandler( void )
|
||||
#endif
|
||||
{
|
||||
MSS_UART_isr( &g_mss_uart0 );
|
||||
NVIC_ClearPendingIRQ( UART0_IRQn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* UART1 interrupt service routine.
|
||||
* UART2_IRQHandler is included within the Cortex-M3 vector table as part of the
|
||||
* Fusion 2 CMSIS.
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void UART1_IRQHandler( void )
|
||||
#else
|
||||
void UART1_IRQHandler( void )
|
||||
#endif
|
||||
{
|
||||
MSS_UART_isr( &g_mss_uart1 );
|
||||
NVIC_ClearPendingIRQ( UART1_IRQn );
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -1,626 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2007 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion Microcontroller Subsystem UART bare metal software driver public API.
|
||||
*
|
||||
* SVN $Revision: 1942 $
|
||||
* SVN $Date: 2009-12-22 17:48:07 +0000 (Tue, 22 Dec 2009) $
|
||||
*/
|
||||
/*=========================================================================*//**
|
||||
@mainpage SmartFusion MSS UART Bare Metal Driver.
|
||||
|
||||
@section intro_sec Introduction
|
||||
The SmartFusion MicroController Subsystem (MSS) includes two UART peripherals
|
||||
for serial communications.
|
||||
This driver provides a set of functions for controlling the MSS UARTs as part
|
||||
of a bare metal system where no operating system is available. These drivers
|
||||
can be adapted for use as part of an operating system but the implementation
|
||||
of the adaptation layer between this driver and the operating system's driver
|
||||
model is outside the scope of this driver.
|
||||
|
||||
@section hw_dependencies Hardware Flow Dependencies
|
||||
The configuration of all features of the MSS UARTs is covered by this driver
|
||||
with the exception of the SmartFusion IOMUX configuration. SmartFusion allows
|
||||
multiple non-concurrent uses of some external pins through IOMUX configuration.
|
||||
This feature allows optimization of external pin usage by assigning external
|
||||
pins for use by either the microcontroller subsystem or the FPGA fabric. The
|
||||
MSS UARTs serial signals are routed through IOMUXes to the SmartFusion device
|
||||
external pins. These IOMUXes are configured automatically by the MSS
|
||||
configurator tool in the hardware flow correctly when the MSS UARTs are enabled
|
||||
in that tool. You must ensure that the MSS UARTs are enabled by the MSS
|
||||
configurator tool in the hardware flow; otherwise the serial inputs and outputs
|
||||
will not be connected to the chip's external pins. For more information on
|
||||
IOMUX, refer to the IOMUX section of the SmartFusion Datasheet.
|
||||
The base address, register addresses and interrupt number assignment for the MSS
|
||||
UART blocks are defined as constants in the SmartFusion CMSIS-PAL You must ensure
|
||||
that the SmartFusion CMSIS-PAL is either included in the software tool chain used
|
||||
to build your project or is included in your project.
|
||||
|
||||
|
||||
@section theory_op Theory of Operation
|
||||
The MSS UART driver uses the SmartFusion "Cortex Microcontroler Software
|
||||
Interface Standard - Peripheral Access Layer" (CMSIS-PAL) to access hadware
|
||||
registers. You must ensure that the SmartFusion CMSIS-PAL is either included
|
||||
in the software toolchain used to build your project or is included in your
|
||||
project. The most up to date SmartFusion CMSIS-PAL files can be obtained using
|
||||
the Actel Firmware Catalog.
|
||||
|
||||
The MSS UART driver functions are logically grouped into three groups:
|
||||
- Initialization functions
|
||||
- Polled transmit and receive functions
|
||||
- Interrupt driven transmit and receive functions
|
||||
|
||||
The MSS UART driver is initialized through a call to the UART_init() function.
|
||||
This function takes the UART's configuration as parameters. The UART_init()
|
||||
function must be called before any other UART driver functions can be called.
|
||||
The first parameter of the UART_init() function is a pointer to one of two
|
||||
global data structures used to store state information for each UART driver.
|
||||
A pointer to these data structures is also used as first parameter to any of
|
||||
the driver functions to identify which UART will be used by the called
|
||||
function. The name of these two data structures are g_mss_uart0 and
|
||||
g_mss_uart1. Therefore any call to a MSS UART function should be of the form
|
||||
UART_function_name( &g_mss_uart0, ... ) or UART_function_name( &g_mss_uart1, ... ).
|
||||
The two SmartFusion MSS UARTs can also be configured to loop back to each
|
||||
other using the MSS_set_loopback() function for debugging purposes.
|
||||
|
||||
Polled operations where the processor constantly poll the UART registers state
|
||||
in order to control data transmit or data receive is performed using functions:
|
||||
- MSS_UART_polled_tx()
|
||||
- MSS_UART_get_rx()
|
||||
|
||||
Interrupt driven operations where the processor sets up transmit or receive
|
||||
then returns to performing some other operation until an interrupts occurs
|
||||
indicating that its attention is required is performed using functions:
|
||||
- MSS_UART_irq_tx()
|
||||
- MSS_UART_tx_complete()
|
||||
- MSS_UART_set_rx_handler()
|
||||
- MSS_UART_get_rx()
|
||||
Interrupt driven transmit is initiated by a call to MSS_UART_irq_tx() specifying
|
||||
the block of data to transmit. The processor can then perform some other
|
||||
operation and later inquire whether transmit has completed by calling the
|
||||
MSS_UART_tx_complete() function.
|
||||
Interrupt driven receive is performed by first registering a receive handler
|
||||
function that will be called by the driver whenever receive data is available.
|
||||
This receive handler function in turns calls the MSS_UART_get_rx() function to
|
||||
actually read the received data.
|
||||
|
||||
*//*=========================================================================*/
|
||||
#ifndef __MSS_UART_H_
|
||||
#define __MSS_UART_H_ 1
|
||||
|
||||
#include "../../CMSIS/a2fxxxm3.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
Baud rates.
|
||||
The following definitions are used to specify standard baud rates as a
|
||||
parameter to the MSS_UART_init() function.
|
||||
*/
|
||||
#define MSS_UART_110_BAUD 110
|
||||
#define MSS_UART_300_BAUD 300
|
||||
#define MSS_UART_1200_BAUD 1200
|
||||
#define MSS_UART_2400_BAUD 2400
|
||||
#define MSS_UART_4800_BAUD 4800
|
||||
#define MSS_UART_9600_BAUD 9600
|
||||
#define MSS_UART_19200_BAUD 19200
|
||||
#define MSS_UART_38400_BAUD 38400
|
||||
#define MSS_UART_57600_BAUD 57600
|
||||
#define MSS_UART_115200_BAUD 115200
|
||||
#define MSS_UART_230400_BAUD 230400
|
||||
#define MSS_UART_460800_BAUD 460800
|
||||
#define MSS_UART_921600_BAUD 921600
|
||||
|
||||
/***************************************************************************//**
|
||||
Data bits length values.
|
||||
|
||||
The following defines are used to build the value of the MSS_UART_init()
|
||||
function line_config parameter.
|
||||
*/
|
||||
#define MSS_UART_DATA_5_BITS 0x00
|
||||
#define MSS_UART_DATA_6_BITS 0x01
|
||||
#define MSS_UART_DATA_7_BITS 0x02
|
||||
#define MSS_UART_DATA_8_BITS 0x03
|
||||
|
||||
/***************************************************************************//**
|
||||
Parity values
|
||||
The following defines are used to build the value of the MSS_UART_init()
|
||||
function line_config parameter.
|
||||
*/
|
||||
#define MSS_UART_NO_PARITY 0x00
|
||||
#define MSS_UART_ODD_PARITY 0x08
|
||||
#define MSS_UART_EVEN_PARITY 0x18
|
||||
#define MSS_UART_STICK_PARITY_0 0x38
|
||||
#define MSS_UART_STICK_PARITY_1 0x28
|
||||
|
||||
/***************************************************************************//**
|
||||
Stop bit values
|
||||
The following defines are used to build the value of the MSS_UART_init()
|
||||
function line_config parameter.
|
||||
*/
|
||||
#define MSS_UART_ONE_STOP_BIT 0x00
|
||||
#define MSS_UART_ONEHALF_STOP_BIT 0x04
|
||||
#define MSS_UART_TWO_STOP_BITS 0x04
|
||||
|
||||
/***************************************************************************//**
|
||||
FIFO trigger sizes
|
||||
This enumeration specifies the number of bytes that must be received before a
|
||||
receive interrupt is generated. This enumeration provides the allowed values for
|
||||
the MSS_UART_set_rx_handler() function trigger_level parameter.
|
||||
*/
|
||||
typedef enum __mss_uart_rx_trig_level_t {
|
||||
MSS_UART_FIFO_SINGLE_BYTE = 0x00,
|
||||
MSS_UART_FIFO_FOUR_BYTES = 0x40,
|
||||
MSS_UART_FIFO_EIGHT_BYTES = 0x80,
|
||||
MSS_UART_FIFO_FOURTEEN_BYTES = 0xC0
|
||||
} mss_uart_rx_trig_level_t;
|
||||
|
||||
/***************************************************************************//**
|
||||
Loopback.
|
||||
This enumeration is used as parameter to function MSS_UART_set_loopback(). It
|
||||
specifies the loopback configuration of the UARTs. Using MSS_UART_LOOPBACK_ON
|
||||
as parameter to function MSS_UART_set_loopback() will set up the UART to locally
|
||||
loopback its Tx and Rx lines.
|
||||
*/
|
||||
typedef enum __mss_uart_loopback_t {
|
||||
MSS_UART_LOOPBACK_OFF = 0,
|
||||
MSS_UART_LOOPBACK_ON = 1
|
||||
} mss_uart_loopback_t;
|
||||
|
||||
/***************************************************************************//**
|
||||
Receive handler prototype.
|
||||
This typedef specifies the prototype of functions that can be registered with
|
||||
this driver as receive handler functions.
|
||||
*/
|
||||
typedef void (*mss_uart_rx_handler_t)(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
mss_uart_instance_t.
|
||||
|
||||
There is one instance of this structure for each instance of the Microcontroller
|
||||
Subsystem's UARTs. Instances of this structure are used to identify a specific
|
||||
UART. A pointer to an instance of the mss_uart_instance_t structure is passed
|
||||
as the first parameter to MSS UART driver functions to identify which UART
|
||||
should perform the requested operation.
|
||||
*/
|
||||
typedef struct {
|
||||
/* CMSIS related defines identifying the UART hardware. */
|
||||
UART_TypeDef * hw_reg; /*!< Pointer to UART registers. */
|
||||
UART_BitBand_TypeDef * hw_reg_bit; /*!< Pointer to UART registers bit band area. */
|
||||
IRQn_Type irqn; /*!< UART's Cortex-M3 NVIC interrupt number. */
|
||||
|
||||
/* transmit related info (used with interrupt driven trnasmit): */
|
||||
const uint8_t * tx_buffer; /*!< Pointer to transmit buffer. */
|
||||
uint32_t tx_buff_size; /*!< Transmit buffer size. */
|
||||
uint32_t tx_idx; /*!< Index within trnamit buffer of next byte to transmit.*/
|
||||
|
||||
/* receive interrupt handler:*/
|
||||
mss_uart_rx_handler_t rx_handler; /*!< Pointer to user registered received handler. */
|
||||
} mss_uart_instance_t;
|
||||
|
||||
/***************************************************************************//**
|
||||
This instance of mss_uart_instance_t holds all data related to the operations
|
||||
performed by UART0. A pointer to g_mss_uart0 is passed as the first parameter
|
||||
to MSS UART driver functions to indicate that UART0 should perform the requested
|
||||
operation.
|
||||
*/
|
||||
extern mss_uart_instance_t g_mss_uart0;
|
||||
|
||||
/***************************************************************************//**
|
||||
This instance of mss_uart_instance_t holds all data related to the operations
|
||||
performed by UART1. A pointer to g_mss_uart1 is passed as the first parameter
|
||||
to MSS UART driver functions to indicate that UART1 should perform the requested
|
||||
operation.
|
||||
*/
|
||||
extern mss_uart_instance_t g_mss_uart1;
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_UART_init() function initializes and configures one of the SmartFusion
|
||||
MSS UARTs with the configuration passed as a parameter. The configuration
|
||||
parameters are the baud_rate which is used to generate the baud value and the
|
||||
line_config which is used to specify the line configuration (bit length, stop
|
||||
bits and parity).
|
||||
|
||||
Example:
|
||||
@code
|
||||
#include "mss_uart.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
MSS_UART_init
|
||||
(
|
||||
&g_mss_uart0,
|
||||
MSS_UART_57600_BAUD,
|
||||
MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT
|
||||
);
|
||||
return(0);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block to be initialized. There are two
|
||||
such data structures, g_mss_uart0 and g_mss_uart1, associated with MSS UART0
|
||||
and MSS UART1 respectively. This parameter must point to either the
|
||||
g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
|
||||
@param baud_rate
|
||||
The baud_rate parameter specifies the baud rate. It can be specified for
|
||||
common baud rates' using the following defines:
|
||||
- MSS_UART_110_BAUD
|
||||
- MSS_UART_300_BAUD
|
||||
- MSS_UART_1200_BAUD
|
||||
- MSS_UART_2400_BAUD
|
||||
- MSS_UART_4800_BAUD
|
||||
- MSS_UART_9600_BAUD
|
||||
- MSS_UART_19200_BAUD
|
||||
- MSS_UART_38400_BAUD
|
||||
- MSS_UART_57600_BAUD
|
||||
- MSS_UART_115200_BAUD
|
||||
- MSS_UART_230400_BAUD
|
||||
- MSS_UART_460800_BAUD
|
||||
- MSS_UART_921600_BAUD
|
||||
Alternatively, any non standard baud rate can be specified by simply passing
|
||||
the actual required baud rate as value for this parameter.
|
||||
|
||||
@param line_config
|
||||
The line_config parameter is the line configuration specifying the bit length,
|
||||
number of stop bits and parity settings. This is a logical OR of one of the
|
||||
following to specify the transmit/receive data bit length:
|
||||
- MSS_UART_DATA_5_BITS
|
||||
- MSS_UART_DATA_6_BITS,
|
||||
- MSS_UART_DATA_7_BITS
|
||||
- MSS_UART_DATA_8_BITS
|
||||
with one of the following to specify the parity setting:
|
||||
- MSS_UART_NO_PARITY
|
||||
- MSS_UART_EVEN_PARITY
|
||||
- MSS_UART_ODD_PARITY
|
||||
- MSS_UART_STICK_PARITY_0
|
||||
- MSS_UART_STICK_PARITY_1
|
||||
with one of the following to specify the number of stop bits:
|
||||
- MSS_UART_ONE_STOP_BIT
|
||||
- MSS_UART_ONEHALF_STOP_BIT
|
||||
- MSS_UART_TWO_STOP_BITS
|
||||
|
||||
@return
|
||||
This function does not return a value.
|
||||
*/
|
||||
void
|
||||
MSS_UART_init
|
||||
(
|
||||
mss_uart_instance_t* this_uart,
|
||||
uint32_t baud_rate,
|
||||
uint8_t line_config
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The function MSS_UART_polled_tx() is used to transmit data. It transfers the
|
||||
contents of the transmitter data buffer, passed as a function parameter, into
|
||||
the UART's hardware transmitter FIFO. It returns when the full content of the
|
||||
transmit data buffer has been transferred to the UART's transmit FIFO.
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_uart0 and g_mss_uart1,
|
||||
associated with MSS UART0 and MSS UART1. This parameter must point to either
|
||||
the g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
@param pbuff
|
||||
The pbuff parameter is a pointer to a buffer containing the data to be
|
||||
transmitted.
|
||||
|
||||
@param tx_size
|
||||
The tx_size parameter specifies the size, in bytes, of the data to be
|
||||
transmitted.
|
||||
|
||||
@return This function does not return a value.
|
||||
*/
|
||||
void
|
||||
MSS_UART_polled_tx
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
const uint8_t * pbuff,
|
||||
uint32_t tx_size
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The function MSS_UART_polled_tx_string() is used to transmit a zero-terminated
|
||||
string. It transfers the text found starting at the address pointed to by
|
||||
p_sz_string into the UART's hardware transmitter FIFO. It returns when the
|
||||
complete string has been transferred to the UART's transmit FIFO.
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_uart0 and g_mss_uart1,
|
||||
associated with MSS UART0 and MSS UART1. This parameter must point to either
|
||||
the g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
@param p_sz_string
|
||||
The p_sz_string parameter is a pointer to a buffer containing the
|
||||
zero-terminated string to be transmitted.
|
||||
|
||||
@return This function does not return a value.
|
||||
*/
|
||||
void
|
||||
MSS_UART_polled_tx_string
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
const uint8_t * p_sz_string
|
||||
);
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
The function MSS_UART_irq_tx() is used to initiate interrupt driven transmit. It
|
||||
returns immediately after making a note of the transmit buffer location and
|
||||
enabling transmit interrupts both at the UART and Cortex-M3 NVIC level.
|
||||
This function takes a pointer to a memory buffer containing the data to
|
||||
transmit as parameter. The memory buffer specified through this pointer
|
||||
should remain allocated and contain the data to transmit until the transmit
|
||||
completion has been detected through calls to function MSS_UART_tx_complete().
|
||||
NOTE: The MSS_UART_irq_tx() function also enables the Transmitter Holding
|
||||
Register Empty (THRE) interrupt and the UART instance interrupt in the
|
||||
Cortex-M3 NVIC as part of its implementation.
|
||||
|
||||
Example:
|
||||
@code
|
||||
#include "mss_uart.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
uint8_t tx_buff[10] = "abcdefghi";
|
||||
MSS_UART_init( &g_mss_uart0, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT );
|
||||
MSS_UART_irq_tx( &g_mss_uart0, tx_buff, sizeof(tx_buff));
|
||||
while ( 0 == MSS_UART_tx_complete( &g_mss_uart0 ) )
|
||||
{
|
||||
;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_uart0 and g_mss_uart1,
|
||||
associated with MSS UART0 and MSS UART1. This parameter must point to either
|
||||
the g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
@param pbuff
|
||||
The pbuff parameter is a pointer to a buffer containing the data to be
|
||||
transmitted.
|
||||
|
||||
@param tx_size
|
||||
The tx_size parameter specifies the size, in bytes, of the data to be
|
||||
transmitted.
|
||||
|
||||
@return
|
||||
This function does not return a value.
|
||||
*/
|
||||
void
|
||||
MSS_UART_irq_tx
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
const uint8_t * pbuff,
|
||||
uint32_t tx_size
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_UART_tx_complete() function is used to find out if interrupt driven
|
||||
transmit previously initiated through a call to MSS_UART_irq_tx() is complete.
|
||||
This is typically used to find out when it is safe to reuse or release the
|
||||
memory buffer holding transmit data.
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_uart0 and g_mss_uart1,
|
||||
associated with MSS UART0 and MSS UART1. This parameter must point to either
|
||||
the g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
@return
|
||||
This function return a non-zero value if transmit has completed, otherwise
|
||||
it returns zero.
|
||||
|
||||
Example:
|
||||
See the MSS_UART_irq_tx() function for an example that uses the
|
||||
MSS_UART_tx_complete() function.
|
||||
*/
|
||||
int8_t
|
||||
MSS_UART_tx_complete
|
||||
(
|
||||
mss_uart_instance_t * this_uart
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_UART_get_rx() function is used to read the content of a UART's receive
|
||||
FIFO. It can be used in polled mode where it is called at regular interval
|
||||
to find out if any data has been received or in interrupt driven mode where
|
||||
it is called as part of a receive handler called by the driver as a result of
|
||||
data being received. This function is non-blocking and will return 0
|
||||
immediately if no data has been received.
|
||||
NOTE: In interrupt driven mode you should call the MSS_UART_get_rx() function
|
||||
as part of the receive handler function that you register with the MSS UART
|
||||
driver through a call to MSS_UART_set_rx_handler().
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_uart0 and g_mss_uart1,
|
||||
associated with MSS UART0 and MSS UART1. This parameter must point to either
|
||||
the g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
@param rx_buff
|
||||
The rx_buff parameter is a pointer to a buffer where the received data will
|
||||
be copied.
|
||||
|
||||
@param buff_size
|
||||
The buff_size parameter specifies the size of the receive buffer in bytes.
|
||||
|
||||
@return
|
||||
This function return the number of bytes that were copied into the rx_buff
|
||||
buffer. It returns 0 if no data has been received.
|
||||
|
||||
Polled mode example:
|
||||
@code
|
||||
int main( void )
|
||||
{
|
||||
uint8_t rx_buff[RX_BUFF_SIZE];
|
||||
uint32_t rx_idx = 0;
|
||||
|
||||
MSS_UART_init( &g_mss_uart0, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
rx_size = MSS_UART_get_rx( &g_mss_uart0, rx_buff, sizeof(rx_buff) );
|
||||
if (rx_size > 0)
|
||||
{
|
||||
process_rx_data( rx_buff, rx_size );
|
||||
}
|
||||
task_a();
|
||||
task_b();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@endcode
|
||||
|
||||
Interrupt driven example:
|
||||
@code
|
||||
int main( void )
|
||||
{
|
||||
MSS_UART_init( &g_mss_uart1, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT );
|
||||
MSS_UART_set_rx_handler( &g_mss_uart1, uart1_rx_handler, MSS_UART_FIFO_SINGLE_BYTE );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
task_a();
|
||||
task_b();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uart1_rx_handler( void )
|
||||
{
|
||||
uint8_t rx_buff[RX_BUFF_SIZE];
|
||||
uint32_t rx_idx = 0;
|
||||
rx_size = MSS_UART_get_rx( &g_mss_uart1, rx_buff, sizeof(rx_buff) );
|
||||
process_rx_data( rx_buff, rx_size );
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
size_t
|
||||
MSS_UART_get_rx
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
uint8_t * rx_buff,
|
||||
size_t buff_size
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_UART_set_rx_handler() function is used to register a receive handler
|
||||
function which will be called by the driver when a UART Received Data Available
|
||||
(RDA) interrupt occurs. You must create and register the handler function to
|
||||
suit your application. The MSS_UART_set_rx_handler() function also enables the UART
|
||||
Received Data Available interrupt and the UART instance interrupt in the
|
||||
Cortex-M3 NVIC as part of its implementation.
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_uart0 and g_mss_uart1,
|
||||
associated with MSS UART0 and MSS UART1. This parameter must point to either
|
||||
the g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
@param handler
|
||||
The handler parameter is a pointer to a receive handler function provided
|
||||
by your application which will be called as a result of a UART Received
|
||||
Data Available interrupt.
|
||||
|
||||
@param trigger_level
|
||||
The trigger_level parameter is the receive FIFO trigger level. This specifies
|
||||
the number of bytes that must be received before the UART triggers a Received
|
||||
Data Available interrupt.
|
||||
|
||||
@return
|
||||
This function does not return a value.
|
||||
|
||||
Example:
|
||||
@code
|
||||
#include "mss_uart.h"
|
||||
|
||||
#define RX_BUFF_SIZE 64
|
||||
|
||||
uint8_t g_rx_buff[RX_BUFF_SIZE];
|
||||
|
||||
void uart0_rx_handler( void )
|
||||
{
|
||||
MSS_UART_get_rx( &g_mss_uart, &g_rx_buff[g_rx_idx], sizeof(g_rx_buff) );
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
MSS_UART_init( &g_mss_uart0, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT );
|
||||
MSS_UART_set_rx_handler( &g_mss_uart0, uart0_rx_handler, MSS_UART_FIFO_SINGLE_BYTE );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
void
|
||||
MSS_UART_set_rx_handler
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
mss_uart_rx_handler_t handler,
|
||||
mss_uart_rx_trig_level_t trigger_level
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_UART_set_loopback() function is used to locally loopback the Tx and Rx
|
||||
lines of a UART.
|
||||
This is not to be confused with the loopback of UART0 to UART1 which can be
|
||||
achieved through the microcontroller subsystem's system registers
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_uart0 and g_mss_uart1,
|
||||
associated with MSS UART0 and MSS UART1. This parameter must point to either
|
||||
the g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
@param loopback
|
||||
The loopback parameter indicates whether or not the UART's transmit and receive lines
|
||||
should be looped back. Allowed values are:
|
||||
- MSS_UART_LOOPBACK_ON
|
||||
- MSS_UART_LOOPBACK_OFF
|
||||
@return
|
||||
This function does not return a value.
|
||||
*/
|
||||
void
|
||||
MSS_UART_set_loopback
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
mss_uart_loopback_t loopback
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MSS_UART_H_ */
|
|
@ -49,6 +49,7 @@
|
|||
#include "apps/httpd/httpd.h"
|
||||
#include "apps/httpd/httpd-cgi.h"
|
||||
#include "apps/httpd/httpd-fs.h"
|
||||
#include "mss_ace.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -209,6 +210,9 @@ unsigned long ulString;
|
|||
static unsigned short generate_io_state( void *arg )
|
||||
{
|
||||
extern long lParTestGetLEDState( unsigned long ulLED );
|
||||
unsigned short usRawVoltage;
|
||||
const ace_channel_handle_t xVoltageChannel = ( ace_channel_handle_t ) 0;
|
||||
|
||||
( void ) arg;
|
||||
|
||||
/* Are the dynamically setable LEDs currently on or off? */
|
||||
|
@ -221,7 +225,8 @@ static unsigned short generate_io_state( void *arg )
|
|||
pcStatus = "";
|
||||
}
|
||||
|
||||
sprintf( uip_appdata, "<input type=\"checkbox\" name=\"LED0\" value=\"1\" %s>LED<p><p>", pcStatus );
|
||||
usRawVoltage = ( unsigned short ) ACE_get_ppe_sample( xVoltageChannel );
|
||||
sprintf( uip_appdata, "<input type=\"checkbox\" name=\"LED0\" value=\"1\" %s>LED<p><p><p>Raw voltage input is %d", pcStatus, usRawVoltage );
|
||||
|
||||
return strlen( uip_appdata );
|
||||
}
|
||||
|
|
|
@ -185,8 +185,8 @@ int main(void)
|
|||
xTaskCreate( prvQueueReceiveTask, ( signed char * ) "Rx", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_RECEIVE_TASK_PRIORITY, NULL );
|
||||
xTaskCreate( prvQueueSendTask, ( signed char * ) "TX", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL );
|
||||
|
||||
/* Create the software timer that is responsible for turning off the LED
|
||||
if the button is not pushed within 5000ms, as described at the top of
|
||||
/* Create the software timer that is responsible for turning off the LED
|
||||
if the button is not pushed within 5000ms, as described at the top of
|
||||
this file. */
|
||||
xLEDTimer = xTimerCreate( ( const signed char * ) "LEDTimer", /* A text name, purely to help debugging. */
|
||||
( 5000 / portTICK_RATE_MS ), /* The timer period, in this case 5000ms (5s). */
|
||||
|
@ -289,8 +289,8 @@ unsigned long ulReceivedValue;
|
|||
if( ulReceivedValue == 100UL )
|
||||
{
|
||||
/* NOTE - accessing the LED port should use a critical section
|
||||
because it is accessed from multiple tasks, and the button interrupt
|
||||
- in this trivial case, for simplicity, the critical section is
|
||||
because it is accessed from multiple tasks, and the button interrupt
|
||||
- in this trivial case, for simplicity, the critical section is
|
||||
omitted. */
|
||||
if( ( ulGPIOState & mainTASK_CONTROLLED_LED ) != 0 )
|
||||
{
|
||||
|
@ -308,6 +308,8 @@ unsigned long ulReceivedValue;
|
|||
|
||||
static void prvSetupHardware( void )
|
||||
{
|
||||
SystemCoreClockUpdate();
|
||||
|
||||
/* Disable the Watch Dog Timer */
|
||||
MSS_WD_disable( );
|
||||
|
||||
|
@ -340,7 +342,7 @@ void vApplicationMallocFailedHook( void )
|
|||
{
|
||||
/* Called if a call to pvPortMalloc() fails because there is insufficient
|
||||
free memory available in the FreeRTOS heap. pvPortMalloc() is called
|
||||
internally by FreeRTOS API functions that create tasks, queues, software
|
||||
internally by FreeRTOS API functions that create tasks, queues, software
|
||||
timers, and semaphores. The size of the FreeRTOS heap is set by the
|
||||
configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */
|
||||
for( ;; );
|
||||
|
@ -364,7 +366,7 @@ void vApplicationIdleHook( void )
|
|||
volatile size_t xFreeStackSpace;
|
||||
|
||||
/* This function is called on each cycle of the idle task. In this case it
|
||||
does nothing useful, other than report the amout of FreeRTOS heap that
|
||||
does nothing useful, other than report the amout of FreeRTOS heap that
|
||||
remains unallocated. */
|
||||
xFreeStackSpace = xPortGetFreeHeapSize();
|
||||
|
||||
|
@ -376,3 +378,21 @@ volatile size_t xFreeStackSpace;
|
|||
reduced accordingly. */
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vMainConfigureTimerForRunTimeStats( void )
|
||||
{
|
||||
/* This function is not used by the Blinky build configuration, but needs
|
||||
to be defined as the Blinky and Full build configurations share a
|
||||
FreeRTOSConfig.h header file. */
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
unsigned long ulGetRunTimeCounterValue( void )
|
||||
{
|
||||
/* This function is not used by the Blinky build configuration, but needs
|
||||
to be defined as the Blinky and Full build configurations share a
|
||||
FreeRTOSConfig.h header file. */
|
||||
return 0UL;
|
||||
}
|
||||
|
||||
|
|
|
@ -148,6 +148,7 @@
|
|||
#include "mss_gpio.h"
|
||||
#include "mss_watchdog.h"
|
||||
#include "mss_timer.h"
|
||||
#include "mss_ace.h"
|
||||
#include "oled.h"
|
||||
|
||||
/* Common demo includes. */
|
||||
|
@ -551,6 +552,9 @@ static void prvSetupHardware( void )
|
|||
|
||||
/* Configure the GPIO for the LEDs. */
|
||||
vParTestInitialise();
|
||||
|
||||
/* ACE Initialization */
|
||||
ACE_init();
|
||||
|
||||
/* Setup the GPIO and the NVIC for the switch used in this simple demo. */
|
||||
NVIC_SetPriority( GPIO8_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
|
||||
|
@ -628,6 +632,7 @@ const unsigned long ulMax32BitValue = 0xffffffffUL;
|
|||
MSS_TIM64_start();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
unsigned long ulGetRunTimeCounterValue( void )
|
||||
{
|
||||
unsigned long long ullCurrentValue;
|
||||
|
|
|
@ -159,8 +159,8 @@ clock_time_t clock_time( void )
|
|||
void vuIP_Task( void *pvParameters )
|
||||
{
|
||||
portBASE_TYPE i;
|
||||
unsigned long ulNewEvent = 0UL;
|
||||
unsigned long ulUIP_Events = 0UL;
|
||||
unsigned long ulNewEvent = 0UL, ulUIP_Events = 0UL;
|
||||
long lPacketLength;
|
||||
|
||||
/* Just to prevent compiler warnings about the unused parameter. */
|
||||
( void ) pvParameters;
|
||||
|
@ -174,11 +174,13 @@ unsigned long ulUIP_Events = 0UL;
|
|||
for( ;; )
|
||||
{
|
||||
/* Is there received data ready to be processed? */
|
||||
uip_len = MSS_MAC_rx_packet();
|
||||
lPacketLength = MSS_MAC_rx_packet();
|
||||
|
||||
/* Statements to be executed if data has been received on the Ethernet. */
|
||||
if( ( uip_len > 0 ) && ( uip_buf != NULL ) )
|
||||
if( ( lPacketLength > 0 ) && ( uip_buf != NULL ) )
|
||||
{
|
||||
uip_len = ( u16_t ) lPacketLength;
|
||||
|
||||
/* Standard uIP loop taken from the uIP manual. */
|
||||
if( xHeader->type == htons( UIP_ETHTYPE_IP ) )
|
||||
{
|
||||
|
@ -286,14 +288,14 @@ xTimerHandle xARPTimer, xPeriodicTimer;
|
|||
xEMACEventQueue = xQueueCreate( uipEVENT_QUEUE_LENGTH, sizeof( unsigned long ) );
|
||||
|
||||
/* Create and start the uIP timers. */
|
||||
xARPTimer = xTimerCreate( ( const signed char * const ) "ARPTimer", /* Just a name that is helpful for debugging, not used by the kernel. */
|
||||
xARPTimer = xTimerCreate( ( signed char * ) "ARPTimer", /* Just a name that is helpful for debugging, not used by the kernel. */
|
||||
( 10000UL / portTICK_RATE_MS ), /* Timer period. */
|
||||
pdTRUE, /* Autor-reload. */
|
||||
( void * ) uipARP_TIMER,
|
||||
prvUIPTimerCallback
|
||||
);
|
||||
|
||||
xPeriodicTimer = xTimerCreate( ( const signed char * const ) "PeriodicTimer",
|
||||
xPeriodicTimer = xTimerCreate( ( signed char * ) "PeriodicTimer",
|
||||
( 500UL / portTICK_RATE_MS ),
|
||||
pdTRUE, /* Autor-reload. */
|
||||
( void * ) uipPERIODIC_TIMER,
|
||||
|
@ -356,7 +358,7 @@ void vEMACWrite( void )
|
|||
{
|
||||
const long lMaxAttempts = 10;
|
||||
long lAttempt;
|
||||
const portTickType xShortDelay = ( 10 / portTICK_RATE_MS );
|
||||
const portTickType xShortDelay = ( 5 / portTICK_RATE_MS );
|
||||
|
||||
/* Try to send data to the Ethernet. Keep trying for a while if data cannot
|
||||
be sent immediately. Note that this will actually cause the data to be sent
|
||||
|
|
Loading…
Reference in a new issue