Update the SmartFusion SoftConsole source code to be the same as the IAR and Keil versions.

pull/1/head
Richard Barry 14 years ago
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,

@ -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

@ -31,7 +31,9 @@ void ace_init_convert(void);
void ACE_init( void )
{
/* Initialize driver's internal data. */
#if (ACE_NB_OF_PPE_FLAGS > 0)
ace_init_flags();
#endif
/* Initialize the data structures used by conversion functions. */
ace_init_convert();

@ -252,7 +252,7 @@
extern "C" {
#endif
#include "../../drivers_config/mss_ace/ace_handles.h"
#include "ace_handles.h"
/*-------------------------------------------------------------------------*//**
Analog to Digital Converter channel IDs.

@ -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,18 +420,29 @@ 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. */
taskENTER_CRITICAL();
{
/* 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. */
taskENTER_CRITICAL();
{
for( ulDescriptor = 0; ulDescriptor < TX_RING_SIZE; ulDescriptor++ )
{
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 = 0u;
@ -442,7 +453,7 @@ MSS_MAC_tx_packet
/* 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;
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;
@ -479,19 +490,24 @@ MSS_MAC_tx_packet
(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_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;
MAC_start_transmission();
MAC->CSR1 = 1u;
}
}
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,7 +610,6 @@ 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 time_out Time out value in milli seconds for receiving.
* if value is #MSS_MAC_BLOCKING, there will be no time out.
@ -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 )
{
/* 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 )
{
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 );
MAC_release_buffer( ( unsigned char * ) g_mss_mac.tx_descriptors[ 1 ].buffer_1 );
/* Just to mark the fact that the buffer has already been released. */
g_mss_mac.tx_descriptors[ 0 ].buffer_1 == NULL;
}
}
}
@ -1447,11 +1470,14 @@ 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. */
while( ( lAttempt <= 1 ) && ( pcReturn == NULL ) )
{
for( lIndex = 0; lIndex < macNUM_BUFFERS; lIndex++ )
{
if( ucMACBufferInUse[ lIndex ] == pdFALSE )
@ -1462,6 +1488,56 @@ unsigned char *pcReturn = NULL;
}
}
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 );
return 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"

@ -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 channels 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 peripherals
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 channels 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
peripherals 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 channels 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 peripherals 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 peripherals 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 peripherals 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

@ -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 );
}

@ -308,6 +308,8 @@ unsigned long ulReceivedValue;
static void prvSetupHardware( void )
{
SystemCoreClockUpdate();
/* Disable the Watch Dog Timer */
MSS_WD_disable( );
@ -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. */
@ -552,6 +553,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 );
NVIC_EnableIRQ( GPIO8_IRQn );
@ -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…
Cancel
Save