I'm using uVision KEIL MDK 5.22 and LPC4357 (CortextM4F 204MHz).
I want to config EMC (External memory controller) of LPC4357 to drive IS42S32800J-6TL SDRAM. It's a 256Mbit 2Meg X 32 X 4 banks sdram with 32bit data bus.
My problem is that i can't use whole of 32MByte of this SDRAM; Only i can drive 16MBytes of it. In other words its likely that i use a 16MByte sdram
My goal is to drive sdram with maximum performance and size (MCU in 204MHz and SDRAMin 102MHz speed).
I'm using KEIL system_LPC43xx.c startup file with the following source.
What is wrong with my configuration that i cant use this SDRAM properly. Also it's not working correctly sometimes. (I use lpcopen memtest to test my sdram). Does any one have the configuration for this ram or something like this.
MCU clock configuration:
/*----------------------------------------------------------------------------
This file configures the clocks as follows:
-----------------------------------------------------------------------------
Clock Unit | Output clock | Source clock | Note
-----------------------------------------------------------------------------
PLL0USB | 480 MHz | XTAL | External crystal # 12 MHz
-----------------------------------------------------------------------------
PLL1 | 204 MHz | XTAL | External crystal # 12 MHz
-----------------------------------------------------------------------------
CPU | 204 MHz | PLL1 | CPU Clock == BASE_M4_CLK
-----------------------------------------------------------------------------
IDIV A | 160 MHz | PLL0USB | For 80/40MHz SPIFI
-----------------------------------------------------------------------------
IDIV B | 25 MHz | ENET_TX_CLK | ENET_TX_CLK # 50MHz
-----------------------------------------------------------------------------
IDIV C | 40 MHz | IDIV A | To SPIFI
-----------------------------------------------------------------------------
IDIV D | 102 MHz | PLL1 | For 102MHz core/SPIFI
-----------------------------------------------------------------------------
IDIV E | 5.3 MHz | PLL1 | To the LCD controller
-----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
Clock source selection definitions (do not change)
*----------------------------------------------------------------------------*/
#define CLK_SRC_32KHZ 0x00
#define CLK_SRC_IRC 0x01
#define CLK_SRC_ENET_RX 0x02
#define CLK_SRC_ENET_TX 0x03
#define CLK_SRC_GP_CLKIN 0x04
#define CLK_SRC_XTAL 0x06
#define CLK_SRC_PLL0U 0x07
#define CLK_SRC_PLL0A 0x08
#define CLK_SRC_PLL1 0x09
#define CLK_SRC_IDIVA 0x0C
#define CLK_SRC_IDIVB 0x0D
#define CLK_SRC_IDIVC 0x0E
#define CLK_SRC_IDIVD 0x0F
#define CLK_SRC_IDIVE 0x10
/*----------------------------------------------------------------------------
Define external input frequency values
*----------------------------------------------------------------------------*/
#define CLK_32KHZ 32768UL /* 32 kHz oscillator frequency */
#define CLK_IRC 12000000UL /* Internal oscillator frequency */
#define CLK_ENET_RX 50000000UL /* Ethernet Rx frequency */
#define CLK_ENET_TX 50000000UL /* Ethernet Tx frequency */
#define CLK_GP_CLKIN 12000000UL /* General purpose clock input freq. */
#define CLK_XTAL 12000000UL /* Crystal oscilator frequency */
/*----------------------------------------------------------------------------
Define clock sources
*----------------------------------------------------------------------------*/
#define PLL1_CLK_SEL CLK_SRC_XTAL /* PLL1 input clock: XTAL */
#define PLL0USB_CLK_SEL CLK_SRC_XTAL /* PLL0USB input clock: XTAL */
#define IDIVA_CLK_SEL CLK_SRC_PLL0U /* IDIVA input clock: PLL0USB */
#define IDIVB_CLK_SEL CLK_SRC_ENET_TX /* IDIVB input clock: ENET TX */
#define IDIVC_CLK_SEL CLK_SRC_IDIVA /* IDIVC input clock: IDIVA */
#define IDIVD_CLK_SEL CLK_SRC_PLL1 /* IDIVD input clock: PLL1 */
#define IDIVE_CLK_SEL CLK_SRC_PLL1 /* IDIVD input clock: PLL1 */
/*----------------------------------------------------------------------------
Configure integer divider values
*----------------------------------------------------------------------------*/
#define IDIVA_IDIV 2 /* Divide input clock by 3 */
#define IDIVB_IDIV 1 /* Divide input clock by 2 */
#define IDIVC_IDIV 3 /* Divide input clock by 4 */
#define IDIVD_IDIV 1 /* Divide input clock by 2 */
#define IDIVE_IDIV 38 /* Divide input clock by 39 */
/*----------------------------------------------------------------------------
Define CPU clock input
*----------------------------------------------------------------------------*/
#define CPU_CLK_SEL CLK_SRC_PLL1 /* Default CPU clock source is PLL1 */
/*----------------------------------------------------------------------------
Configure external memory controller options
*----------------------------------------------------------------------------*/
#define USE_EXT_STAT_MEM_CS0 0 /* Use ext. static memory with CS0 */
#define USE_EXT_DYN_MEM_CS0 1 /* Use ext. dynamic memory with CS0 */
/*----------------------------------------------------------------------------
* Configure PLL1
*----------------------------------------------------------------------------
* Integer mode:
* - PLL1_DIRECT = 0 (Post divider enabled)
* - PLL1_FBSEL = 1 (Feedback divider runs from PLL output)
* - Output frequency:
* FCLKOUT = (FCLKIN / N) * M
* FCCO = FCLKOUT * 2 * P
*
* Non-integer:
* - PLL1_DIRECT = 0 (Post divider enabled)
* - PLL1_FBSEL = 0 (Feedback divider runs from CCO clock)
* - Output frequency:
* FCLKOUT = (FCLKIN / N) * M / (2 * P)
* FCCO = FCLKOUT * 2 * P
*
* Direct mode:
* - PLL1_DIRECT = 1 (Post divider disabled)
* - PLL1_FBSEL = dont care (Feedback divider runs from CCO clock)
* - Output frequency:
* FCLKOUT = (FCLKIN / N) * M
* FCCO = FCLKOUT
*
*----------------------------------------------------------------------------
* PLL1 requirements:
* | Frequency | Minimum | Maximum | Note |
* | FCLKIN | 1MHz | 25MHz | Clock source is external crystal |
* | FCLKIN | 1MHz | 50MHz | |
* | FCCO | 156MHz | 320MHz | |
* | FCLKOUT | 9.75MHz | 320MHz | |
*----------------------------------------------------------------------------
* Configuration examples:
* | Fclkout | Fcco | N | M | P | DIRECT | FBSEL | BYPASS |
* | 36MHz | 288MHz | 1 | 24 | 4 | 0 | 0 | 0 |
* | 72MHz | 288MHz | 1 | 24 | 2 | 0 | 0 | 0 |
* | 100MHz | 200MHz | 3 | 50 | 1 | 0 | 0 | 0 |
* | 120MHz | 240MHz | 1 | 20 | 1 | 0 | 0 | 0 |
* | 160MHz | 160MHz | 3 | 40 | x | 1 | 0 | 0 |
* | 180MHz | 180MHz | 1 | 15 | x | 1 | 0 | 0 |
* | 204MHz | 204MHz | 1 | 17 | x | 1 | 0 | 0 |
*----------------------------------------------------------------------------
* Relations beetwen PLL dividers and definitions:
* N = PLL1_NSEL + 1, M = PLL1_MSEL + 1, P = 2 ^ PLL1_PSEL
*----------------------------------------------------------------------------*/
/* PLL1 output clock: 204MHz, Fcco: 204MHz, N = 1, M = 17, P = x */
#define PLL1_NSEL 0 /* Range [0 - 3]: Pre-divider ratio N */
#define PLL1_MSEL 16 /* Range [0 - 255]: Feedback-divider ratio M */
#define PLL1_PSEL 0 /* Range [0 - 3]: Post-divider ratio P */
#define PLL1_BYPASS 0 /* 0: Use PLL, 1: PLL is bypassed */
#define PLL1_DIRECT 1 /* 0: Use PSEL, 1: Don't use PSEL */
#define PLL1_FBSEL 0 /* 0: FCCO is used as PLL feedback */
/* 1: FCLKOUT is used as PLL feedback */
/*----------------------------------------------------------------------------
* Configure PLL0USB
*----------------------------------------------------------------------------
*
* Normal operating mode without post-divider and without pre-divider
* - PLL0USB_DIRECTI = 1
* - PLL0USB_DIRECTO = 1
* - PLL0USB_BYPASS = 0
* - Output frequency:
* FOUT = FIN * 2 * M
* FCCO = FOUT
*
* Normal operating mode with post-divider and without pre-divider
* - PLL0USB_DIRECTI = 1
* - PLL0USB_DIRECTO = 0
* - PLL0USB_BYPASS = 0
* - Output frequency:
* FOUT = FIN * (M / P)
* FCCO = FOUT * 2 * P
*
* Normal operating mode without post-divider and with pre-divider
* - PLL0USB_DIRECTI = 0
* - PLL0USB_DIRECTO = 1
* - PLL0USB_BYPASS = 0
* - Output frequency:
* FOUT = FIN * 2 * M / N
* FCCO = FOUT
*
* Normal operating mode with post-divider and with pre-divider
* - PLL0USB_DIRECTI = 0
* - PLL0USB_DIRECTO = 0
* - PLL0USB_BYPASS = 0
* - Output frequency:
* FOUT = FIN * M / (P * N)
* FCCO = FOUT * 2 * P
*----------------------------------------------------------------------------
* PLL0 requirements:
* | Frequency | Minimum | Maximum | Note |
* | FCLKIN | 14kHz | 25MHz | Clock source is external crystal |
* | FCLKIN | 14kHz | 150MHz | |
* | FCCO | 275MHz | 550MHz | |
* | FCLKOUT | 4.3MHz | 550MHz | |
*----------------------------------------------------------------------------
* Configuration examples:
* | Fclkout | Fcco | N | M | P | DIRECTI | DIRECTO | BYPASS |
* | 120MHz | 480MHz | x | 20 | 2 | 1 | 0 | 0 |
* | 480MHz | 480MHz | 1 | 20 | 1 | 1 | 1 | 0 |
*----------------------------------------------------------------------------*/
/* PLL0USB output clock: 480MHz, Fcco: 480MHz, N = 1, M = 20, P = 1 */
#define PLL0USB_N 1 /* Range [1 - 256]: Pre-divider */
#define PLL0USB_M 20 /* Range [1 - 2^15]: Feedback-divider */
#define PLL0USB_P 1 /* Range [1 - 32]: Post-divider */
#define PLL0USB_DIRECTI 1 /* 0: Use N_DIV, 1: Don't use N_DIV */
#define PLL0USB_DIRECTO 1 /* 0: Use P_DIV, 1: Don't use P_DIV */
#define PLL0USB_BYPASS 0 /* 0: Use PLL, 1: PLL is bypassed */
External memory configuration:
/*----------------------------------------------------------------------------
External Memory Controller Definitions
*----------------------------------------------------------------------------*/
#define SDRAM_ADDR_BASE 0x28000000 /* SDRAM base address */
/* Write Mode register macro */
#define WR_MODE(x) (*((volatile uint32_t *)(SDRAM_ADDR_BASE | (x))))
/* Pin Settings: Glith filter DIS, Input buffer EN, Fast Slew Rate, No Pullup */
#define EMC_PIN_SET ((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4))
#define EMC_NANOSEC(ns, freq, div) (((uint64_t)(ns) * ((freq)/((div)+1)))/1000000000)
#define EMC_CLK_DLY_TIM_2 (0x7777) /* 3.5 ns delay for the EMC clock out */
#define EMC_CLK_DLY_TIM_0 (0x0000) /* No delay for the EMC clock out */
typedef void (*emcdivby2) (volatile uint32_t *creg6, volatile uint32_t *emcdiv, uint32_t cfg);
const uint16_t emcdivby2_opc[] = {
0x6803, /* LDR R3,[R0,#0] ; Load CREG6 */
0xF443,0x3380, /* ORR R3,R3,#0x10000 ; Set Divided by 2 */
0x6003, /* STR R3,[R0,#0] ; Store CREG6 */
0x600A, /* STR R2,[R1,#0] ; EMCDIV_CFG = cfg */
0x684B, /* loop LDR R3,[R1,#4] ; Load EMCDIV_STAT */
0x07DB, /* LSLS R3,R3,#31 ; Check EMCDIV_STAT.0 */
0xD0FC, /* BEQ loop ; Jump if 0 */
0x4770, /* BX LR ; Exit */
0,
};
#define emcdivby2_szw ((sizeof(emcdivby2_opc)+3)/4)
#define emcdivby2_ram 0x10000000
/*----------------------------------------------------------------------------
Initialize external memory controller
*----------------------------------------------------------------------------*/
void SystemInit_ExtMemCtl (void) {
uint32_t emcdivby2_buf[emcdivby2_szw];
uint32_t div, n;
/* Select and enable EMC branch clock */
LPC_CCU1->CLK_M4_EMC_CFG = (1 << 2) | (1 << 1) | 1;
while (!(LPC_CCU1->CLK_M4_EMC_STAT & 1));
/* Set EMC clock output delay */
if (SystemCoreClock < 80000000UL) {
LPC_SCU->EMCDELAYCLK = EMC_CLK_DLY_TIM_0; /* No EMC clock out delay */
}
else {
LPC_SCU->EMCDELAYCLK = EMC_CLK_DLY_TIM_2; /* 2.0 ns EMC clock out delay */
}
/* Configure EMC port pins */
LPC_SCU->SFSP1_0 = EMC_PIN_SET | 2; /* P1_0: A5 */
LPC_SCU->SFSP1_1 = EMC_PIN_SET | 2; /* P1_1: A6 */
LPC_SCU->SFSP1_2 = EMC_PIN_SET | 2; /* P1_2: A7 */
// LPC_SCU->SFSP1_3 = EMC_PIN_SET | 3; /* P1_3: OE */
// LPC_SCU->SFSP1_4 = EMC_PIN_SET | 3; /* P1_4: BLS0 */
LPC_SCU->SFSP1_5 = EMC_PIN_SET | 3; /* P1_5: CS0 */
LPC_SCU->SFSP1_6 = EMC_PIN_SET | 3; /* P1_6: WE */
LPC_SCU->SFSP1_7 = EMC_PIN_SET | 3; /* P1_7: D0 */
LPC_SCU->SFSP1_8 = EMC_PIN_SET | 3; /* P1_8: D1 */
LPC_SCU->SFSP1_9 = EMC_PIN_SET | 3; /* P1_9: D2 */
LPC_SCU->SFSP1_10 = EMC_PIN_SET | 3; /* P1_10: D3 */
LPC_SCU->SFSP1_11 = EMC_PIN_SET | 3; /* P1_11: D4 */
LPC_SCU->SFSP1_12 = EMC_PIN_SET | 3; /* P1_12: D5 */
LPC_SCU->SFSP1_13 = EMC_PIN_SET | 3; /* P1_13: D6 */
LPC_SCU->SFSP1_14 = EMC_PIN_SET | 3; /* P1_14: D7 */
LPC_SCU->SFSP2_0 = EMC_PIN_SET | 2; /* P2_0: A13 */
LPC_SCU->SFSP2_1 = EMC_PIN_SET | 2; /* P2_1: A12 */
LPC_SCU->SFSP2_2 = EMC_PIN_SET | 2; /* P2_2: A11 */
LPC_SCU->SFSP2_6 = EMC_PIN_SET | 2; /* P2_6: A10 */
LPC_SCU->SFSP2_7 = EMC_PIN_SET | 3; /* P2_7: A9 */
LPC_SCU->SFSP2_8 = EMC_PIN_SET | 3; /* P2_8: A8 */
LPC_SCU->SFSP2_9 = EMC_PIN_SET | 3; /* P2_9: A0 */
LPC_SCU->SFSP2_10 = EMC_PIN_SET | 3; /* P2_10: A1 */
LPC_SCU->SFSP2_11 = EMC_PIN_SET | 3; /* P2_11: A2 */
LPC_SCU->SFSP2_12 = EMC_PIN_SET | 3; /* P2_12: A3 */
LPC_SCU->SFSP2_13 = EMC_PIN_SET | 3; /* P2_13: A4 */
LPC_SCU->SFSP5_0 = EMC_PIN_SET | 2; /* P5_0: D12 */
LPC_SCU->SFSP5_1 = EMC_PIN_SET | 2; /* P5_1: D13 */
LPC_SCU->SFSP5_2 = EMC_PIN_SET | 2; /* P5_2: D14 */
LPC_SCU->SFSP5_3 = EMC_PIN_SET | 2; /* P5_3: D15 */
LPC_SCU->SFSP5_4 = EMC_PIN_SET | 2; /* P5_4: D8 */
LPC_SCU->SFSP5_5 = EMC_PIN_SET | 2; /* P5_5: D9 */
LPC_SCU->SFSP5_6 = EMC_PIN_SET | 2; /* P5_6: D10 */
LPC_SCU->SFSP5_7 = EMC_PIN_SET | 2; /* P5_7: D11 */
// LPC_SCU->SFSP6_1 = EMC_PIN_SET | 1; /* P6_1: DYCS1 */
// LPC_SCU->SFSP6_2 = EMC_PIN_SET | 1; /* P6_2: CKEOUT1 */
// LPC_SCU->SFSP6_3 = EMC_PIN_SET | 3; /* P6_3: CS1 */
LPC_SCU->SFSP6_4 = EMC_PIN_SET | 3; /* P6_4: CAS */
LPC_SCU->SFSP6_5 = EMC_PIN_SET | 3; /* P6_5: RAS */
// LPC_SCU->SFSP6_6 = EMC_PIN_SET | 1; /* P6_6: BLS1 */
// LPC_SCU->SFSP6_7 = EMC_PIN_SET | 1; /* P6_7: A15 */
LPC_SCU->SFSP6_8 = EMC_PIN_SET | 1; /* P6_8: A14 */
LPC_SCU->SFSP6_9 = EMC_PIN_SET | 3; /* P6_9: DYCS0 */
LPC_SCU->SFSP6_10 = EMC_PIN_SET | 3; /* P6_10: DQMOUT1 */
LPC_SCU->SFSP6_11 = EMC_PIN_SET | 3; /* P6_11: CKEOUT0 */
LPC_SCU->SFSP6_12 = EMC_PIN_SET | 3; /* P6_12: DQMOUT0 */
// LPC_SCU->SFSPA_4 = EMC_PIN_SET | 3; /* PA_4: A23 */
LPC_SCU->SFSPD_0 = EMC_PIN_SET | 2; /* PD_0: DQMOUT2 */
// LPC_SCU->SFSPD_1 = EMC_PIN_SET | 2; /* PD_1: CKEOUT2 */
LPC_SCU->SFSPD_2 = EMC_PIN_SET | 2; /* PD_2: D16 */
LPC_SCU->SFSPD_3 = EMC_PIN_SET | 2; /* PD_3: D17 */
LPC_SCU->SFSPD_4 = EMC_PIN_SET | 2; /* PD_4: D18 */
LPC_SCU->SFSPD_5 = EMC_PIN_SET | 2; /* PD_5: D19 */
LPC_SCU->SFSPD_6 = EMC_PIN_SET | 2; /* PD_6: D20 */
LPC_SCU->SFSPD_7 = EMC_PIN_SET | 2; /* PD_7: D21 */
LPC_SCU->SFSPD_8 = EMC_PIN_SET | 2; /* PD_8: D22 */
LPC_SCU->SFSPD_9 = EMC_PIN_SET | 2; /* PD_9: D23 */
// LPC_SCU->SFSPD_10 = EMC_PIN_SET | 2; /* PD_10: BLS3 */
// LPC_SCU->SFSPD_11 = EMC_PIN_SET | 2; /* PD_11: CS3 */
// LPC_SCU->SFSPD_12 = EMC_PIN_SET | 2; /* PD_12: CS2 */
// LPC_SCU->SFSPD_13 = EMC_PIN_SET | 2; /* PD_13: BLS2 */
// LPC_SCU->SFSPD_14 = EMC_PIN_SET | 2; /* PD_14: DYCS2 */
// LPC_SCU->SFSPD_15 = EMC_PIN_SET | 2; /* PD_15: A17 */
// LPC_SCU->SFSPD_16 = EMC_PIN_SET | 2; /* PD_16: A16 */
// LPC_SCU->SFSPE_0 = EMC_PIN_SET | 3; /* PE_0: A18 */
// LPC_SCU->SFSPE_1 = EMC_PIN_SET | 3; /* PE_1: A19 */
// LPC_SCU->SFSPE_2 = EMC_PIN_SET | 3; /* PE_2: A20 */
// LPC_SCU->SFSPE_3 = EMC_PIN_SET | 3; /* PE_3: A21 */
// LPC_SCU->SFSPE_4 = EMC_PIN_SET | 3; /* PE_4: A22 */
LPC_SCU->SFSPE_5 = EMC_PIN_SET | 3; /* PE_5: D24 */
LPC_SCU->SFSPE_6 = EMC_PIN_SET | 3; /* PE_6: D25 */
LPC_SCU->SFSPE_7 = EMC_PIN_SET | 3; /* PE_7: D26 */
LPC_SCU->SFSPE_8 = EMC_PIN_SET | 3; /* PE_8: D27 */
LPC_SCU->SFSPE_9 = EMC_PIN_SET | 3; /* PE_9: D28 */
LPC_SCU->SFSPE_10 = EMC_PIN_SET | 3; /* PE_10: D29 */
LPC_SCU->SFSPE_11 = EMC_PIN_SET | 3; /* PE_11: D30 */
LPC_SCU->SFSPE_12 = EMC_PIN_SET | 3; /* PE_12: D31 */
LPC_SCU->SFSPE_13 = EMC_PIN_SET | 3; /* PE_13: DQMOUT3 */
// LPC_SCU->SFSPE_14 = EMC_PIN_SET | 3; /* PE_14: DYCS3 */
// LPC_SCU->SFSPE_15 = EMC_PIN_SET | 3; /* PE_15: CKEOUT3 */
LPC_EMC->CONTROL = 0x00000001; /* EMC Enable */
LPC_EMC->CONFIG = 0x00000000; /* Little-endian, Clock Ratio 1:1 */
div = 0;
if (SystemCoreClock > 120000000UL) {
/* Use EMC clock divider and EMC clock output delay */
div = 1;
/* Following code must be executed in RAM to ensure stable operation */
/* LPC_CCU1->CLK_M4_EMCDIV_CFG = (1 << 5) | (1 << 2) | (1 << 1) | 1; */
/* LPC_CREG->CREG6 |= (1 << 16); // EMC_CLK_DIV divided by 2 */
/* while (!(LPC_CCU1->CLK_M4_EMCDIV_STAT & 1)); */
/* This code configures EMC clock divider and is executed in RAM */
for (n = 0; n < emcdivby2_szw; n++) {
emcdivby2_buf[n] = *((uint32_t *)emcdivby2_ram + n);
*((uint32_t *)emcdivby2_ram + n) = *((uint32_t *)emcdivby2_opc + n);
}
__ISB();
((emcdivby2 )(emcdivby2_ram+1))(&LPC_CREG->CREG6, &LPC_CCU1->CLK_M4_EMCDIV_CFG, (1 << 5) | (1 << 2) | (1 << 1) | 1);
for (n = 0; n < emcdivby2_szw; n++) {
*((uint32_t *)emcdivby2_ram + n) = emcdivby2_buf[n];
}
}
/* Configure EMC clock-out pins */
LPC_SCU->SFSCLK_0 = EMC_PIN_SET | 0; /* CLK0 */
LPC_SCU->SFSCLK_1 = EMC_PIN_SET | 0; /* CLK1 */
LPC_SCU->SFSCLK_2 = EMC_PIN_SET | 0; /* CLK2 */
LPC_SCU->SFSCLK_3 = EMC_PIN_SET | 0; /* CLK3 */
/* Static memory configuration (chip select 0) */
#if (USE_EXT_STAT_MEM_CS0)
LPC_EMC->STATICCONFIG0 = (1 << 7) | /* Byte lane state: use WE signal */
(2 << 0) | /* Memory width 32-bit */
(1 << 3); /* Async page mode enable */
LPC_EMC->STATICWAITOEN0 = (0 << 0) ; /* Wait output enable: No delay */
LPC_EMC->STATICWAITPAGE0 = 2;
/* Set Static Memory Read Delay for 90ns External NOR Flash */
LPC_EMC->STATICWAITRD0 = 1 + EMC_NANOSEC(90, SystemCoreClock, div);
LPC_EMC->STATICCONFIG0 |= (1 << 19) ; /* Enable buffer */
#endif
/* Dynamic memory configuration (chip select 0) */
#if (USE_EXT_DYN_MEM_CS0)
/* Set Address mapping: 128Mb(4Mx32), 4 banks, row len = 12, column len = 8 */
LPC_EMC->DYNAMICCONFIG0 = (1 << 14) | /* AM[14] = 1 */
(0 << 12) | /* AM[12] = 0 */
(3 << 9) | /* AM[11:9] = 2 */
(2 << 7) ; /* AM[8:7] = 2 */
LPC_EMC->DYNAMICRASCAS0 = 0x00000303; /* Latency: RAS 3, CAS 3 CCLK cyc.*/
LPC_EMC->DYNAMICREADCONFIG = 0x00000001; /* Command delayed by 1/2 CCLK */
LPC_EMC->DYNAMICRP = EMC_NANOSEC (20, SystemCoreClock, div);
LPC_EMC->DYNAMICRAS = EMC_NANOSEC (42, SystemCoreClock, div);
LPC_EMC->DYNAMICSREX = EMC_NANOSEC (63, SystemCoreClock, div);
LPC_EMC->DYNAMICAPR = EMC_NANOSEC (70, SystemCoreClock, div);
LPC_EMC->DYNAMICDAL = EMC_NANOSEC (70, SystemCoreClock, div);
LPC_EMC->DYNAMICWR = EMC_NANOSEC (30, SystemCoreClock, div);
LPC_EMC->DYNAMICRC = EMC_NANOSEC (63, SystemCoreClock, div);
LPC_EMC->DYNAMICRFC = EMC_NANOSEC (63, SystemCoreClock, div);
LPC_EMC->DYNAMICXSR = EMC_NANOSEC (63, SystemCoreClock, div);
LPC_EMC->DYNAMICRRD = EMC_NANOSEC (14, SystemCoreClock, div);
LPC_EMC->DYNAMICMRD = EMC_NANOSEC (30, SystemCoreClock, div);
WaitUs (100);
LPC_EMC->DYNAMICCONTROL = 0x00000183; /* Issue NOP command */
WaitUs (10);
LPC_EMC->DYNAMICCONTROL = 0x00000103; /* Issue PALL command */
WaitUs (1);
LPC_EMC->DYNAMICCONTROL = 0x00000183; /* Issue NOP command */
WaitUs (1);
LPC_EMC->DYNAMICREFRESH = EMC_NANOSEC( 200, SystemCoreClock, div) / 16 + 1;
WaitUs (10);
LPC_EMC->DYNAMICREFRESH = EMC_NANOSEC(15625, SystemCoreClock, div) / 16 + 1;
WaitUs (10);
LPC_EMC->DYNAMICCONTROL = 0x00000083; /* Issue MODE command */
/* Mode register: Burst Length: 4, Burst Type: Sequential, CAS Latency: 3 */
WR_MODE(((3 << 4) | 2) << 12);
WaitUs (10);
LPC_EMC->DYNAMICCONTROL = 0x00000002; /* Issue NORMAL command */
LPC_EMC->DYNAMICCONFIG0 |= (1 << 19); /* Enable buffer */
#endif
}
SDRam schematic:
SDRAM schematic
Any suggestion about config this sdram or using LPCOpen system_init are welcome.
Tanks
I fixed the problem.
The problem was in system_LPC43xx.c external memory setup.
It has 2 problem. the first one is configuration of address mapping of sdram.
it should be:
/* Set Address mapping: 256Mb(8Mx32), 4 banks, row len = 12, column len = 9 */
LPC_EMC->DYNAMICCONFIG0 = (1 << 14) | /* AM[14] = 1 */
(0 << 12) | /* AM[12] = 0 */
(2 << 9) | /* AM[11:9] = 2 */
(1 << 7) ; /* AM[8:7] = 1 */
the second one is SDRAM mode register burst length set-up (section 23.8.5.2 in the LPC4357 user manual). It should be:
/* Mode register: Burst Length: 4, Burst Type: Sequential, CAS Latency: 3 */
/* OFFSET = 13 = 9 + 2 + 2 = number of columns + total bus width + bank select bits (RBC mode) */
WR_MODE(((3 << 4) | 2) << 13);
If someone has any problem about EMC setup i can help (because of many readings and experimenting, I'm an EMC man now :) )
Related
In C language, I want to fill two 8-bit variables "a" and "b" with bits coming from a 16-bit variable "c".
The bits in the 16 bits variable are shuffled without any logical order, which can be for example :
a.4 | b.2 | b.6 | b.0 | a.0 | a.7 | a.6 | b.1 | b.2 | b.7 | b.4 | a.5 | a.1 | a.2 | b.3 | b.5
Is there a way to do that?
The goal is to have a quite lisible look-up table.
This code randomizes and shuffles bits in c after copying initial, you stated it is intended to be used in a embedded system but you didn't provide any information about which embedded system it is, it could be an arduino, it could be a obscure system from 80s, it could be a diy pcb with a random stm32 attached to it, we can't know :)
// Code is under public domain, use it like what you want
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <time.h>
int main() {
srand(time(NULL));
uint16_t initial = 4040; /* 24 will be shuffled */
uint16_t c = 0;
/* shuffle bits */
for(unsigned i = 0; i < sizeof(uint16_t) * 8; ++i) {
c ^= initial & (1 << (rand() % 16));
}
uint8_t a = 0;
uint8_t b = 0;
a = ((unsigned char*)&c)[0];
b = ((unsigned char*)&c)[1];
for(unsigned char i = 0; i < sizeof(uint16_t) * 8; ++i) {
printf("%c.%d = %d | ", ('a' * ((i < 8))) + ('b' * ((i >= 8))), ((i + 1) * (i < 8)) + ((i + 1 - 8) * (i >= 8)), ((a >> i)) & 1);
}
return 0;
}
This code will print this (obviously yours going to be random):
a.1 = 1 | a.2 = 0 | a.3 = 1 | a.4 = 1 | a.5 = 0 | a.6 = 1 | a.7 = 1 | a.8 = 1 | b.1 = 0 | b.2 = 0 | b.3 = 0 | b.4 = 1 | b.5 = 0 | b.6 = 1 | b.7 = 0 | b.8 = 0 |
Here is the code,
I dont understand how to change it to a 10-bit ADC.
my guess is something along the line of 16-bits and just ignore the last 6, but i have no clue .
If someone can offer advice on how to change it, great.
Im really lost.
I've read somethings about this, but I've just gotten more confused the more I read.
Here is the led arrangement
Any other information needed just ask
#include <xc.h>
/* Configuration Word */
#pragma config FOSC = INTOSCIO// Clock
#pragma config WDTE = OFF //
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = OFF // Brown Out Detect (BOR disabled)
#pragma config IESO = OFF // Internal External Switchover bit (Internal External Switchover mode is disabled)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled)
// CONFIG --- Configuration Word --- END
void PORTA_init(void);
void ADC_Disp(void);
void Delay_LED_On(void);
int ADC_Value = 0;
const char PORTA_Value[8] = {
0b010000, // D0
0b100000, // D1
0b010000, // D2
0b000100, // D3
0b100000, // D4
0b000100, // D5
0b000100, // D6
0b000010}; // D7
const char TRISA_Value[8] = {
0b001111, // D0
0b001111, // D1
0b101011, // D2
0b101011, // D3
0b011011, // D4
0b011011, // D5
0b111001, // D6
0b111001}; // D7
main()
{
PORTA_init();
ANSEL = 1; // Just RA0 is an Analog Input
TRISA0 = 1; // Corresponding TRIS bit is set as input
ADCON0 = 0b00000001; // Turn on the ADC
// Bit 7 - Left Justified Sample
// Bit 6 - Use VDD
// Bit 4:2 - Channel 0
// Bit 1 - Do not Start
// Bit 0 - Turn on ADC
ADCON1 = 0b00010000; // Select the Clock as Fosc/8
ADC_Disp();
GO_DONE = 1; // Start A/D Conversion
while(1 == 1) // Loop Forever
{
if (GO_DONE == 0) // Is A/D Conversion complete?
{ ADC_Disp(); // Display A/D Conversion Results
ADC_Value = ADRESH; // Get new A/D value
GO_DONE = 1; // Start the next A/D Conversion
}
else // A/D Conversion still in progress
ADC_Disp();
}
}
/******** END OF main ROUTINE ***************************/
void PORTA_init(void)
{
PORTA = 0; // All PORTA Pins are low
CMCON0 = 7; // Turn off Comparators
ANSEL = 0; // Turn off ADC
return;
}
/******** END OF PORTA_init ****************************/
/********************************************************
* Function: ADC_Disp
*
* Description: Displays the value of A/D Conversion on D0 - D7
*
* Notes:
*
*
*
* Returns: None
*
********************************************************/
void ADC_Disp(void)
{
int i;
for (i = 0; i < 8; i++ )
{ // Loop through Each of the 8 LEDS
Delay_LED_On(); // Allows time for individual LEDs to light
if ((ADC_Value & (1 << i)) == 0)
PORTA = 0;
else
PORTA = PORTA_Value[i];
TRISA = TRISA_Value[i];
} //
return;
}
/******** END OF ADC_Disp *************************/
void Delay_LED_On(void)
{
int j;
for (j = 0; j < 60; j++); // Display "On" Loop
return;
}
/******** END OF Delay_LED_On *************************/
By default ADC is configured to give left justified results(ADFM=0). The lower 8 bits are in ADRESH and the upper 2 bits are stored in ADRESL. You can read both addresses into a 16 bit variable and discard the upper 6 bits.
uint16_t ADC_Value = ( (ADRESH << 8) | ADRESL ) >> 6;
Pretty easy:
use a right justified result
ADCON0 = 0b10000001; // Turn on the ADC
// Bit 7 - Right Justified Sample
// Bit 6 - Use VDD
// Bit 4:2 - Channel 0
// Bit 1 - Do not Start
// Bit 0 - Turn on ADC
And then a 16 Bit result:
uint16_t ADC_result;
ADC_result = (uint16_t)(ADRESH <<8) + ADRESL;
Know you 10 Bit result is in the lower 10 Bits of ADC_result.
Another issue in your code: look at your braces and indent your code carefully.
This won't work:
if ((ADC_Value & (1 << i)) == 0)
PORTA = 0;
else
PORTA = PORTA_Value[i];
TRISA = TRISA_Value[i];
One way of obtaining 10 bits out of an 8 bits ADC is : Four samples of ADC data of 8 bits can be averaged and then multiplied by 4 to get a 10 bits precision data. So overall conversion rate of 10 bit data seems like 1/4th of the conversion rate of 8 bits ADC.
This code will display 10-bits of the ADC value in 10 Charlieplexed LEDs:
/*
* File: main.c
* Author: dan1138
* Target: PIC16F684
* Compiler: XC8 v2.20
* IDE: MPLABX v5.25
*
* Description:
*
* Display the upper 10-bits of the ADC conversion
* from analog input from RA0 on 12 charlieplexed
* LEDs connected to outputs RA1,RA2,RA4,RA5.
*
* PIC16F684
* +------------:_:------------+
* GND -> 1 : VDD VSS : 14 <- 5v0
* DRV5 <> 2 : RA5/T1CKI PGD/AN0/RA0 : 13 <> POT
* DRV4 <> 3 : RA4/AN3 PGC/AN1/RA1 : 12 <> DRV1
* VPP -> 4 : RA3/VPP AN2/RA2 : 11 <> DRV2
* <> 5 : RC5/CPP1 AN4/RC0 : 10 <>
* <> 6 : RC4/C2OUT AN5/RC1 : 9 <>
* <> 7 : RC3/AN7 AN6 RC2 : 8 <>
* +---------------------------:
* DIP-14
*
* 150 OHM
* DRV4 ----/\/\/\-------+---------+---------+---------+-----------------------------+---------+
* : : : : : :
* : : : : : :
* --- --- --- --- : :
* LED1 / \ LED0 \ / LED3 / \ LED2 \ / : :
* --- --- --- --- : :
* : : : : : :
* 150 OHM : : : : : :
* DRV5 ----/\/\/\-------+---------+-------- : ------- : --------+---------+ : :
* : : : : : : : :
* : : : : : : : :
* --- --- : : : : --- ---
* LED5 / \ LED4 \ / : : : : LED11 / \ LED10 \ /
* --- --- : : : : --- ---
* : : : : : : : :
* 150 OHM : : : : : : : :
* DRV2 ----/\/\/\-------+---------+---------+---------+ : : : :
* : : : : : :
* : : : : : :
* --- --- --- --- : :
* LED7 / \ LED6 \ / LED9 / \ LED8 \ / : :
* --- --- --- --- : :
* : : : : : :
* 150 OHM : : : : : :
* DRV1 ----/\/\/\-------+---------+-----------------------------+---------+---------+---------+
*
*
* POT -----/\/\/\--+-------+
* 1K : :
* : --- 1nF
* : ---
* v :
* 5v0 ----------/\/\/\-----+---- GND
* 10K
*
*
* Notes:
* Charlieplexing, see https://en.wikipedia.org/wiki/Charlieplexing
*
* Created on July 13, 2019, 6:09 PM
*/
#pragma config FOSC = INTOSCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = ON
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
#include <xc.h>
#include <stdint.h>
#define _XTAL_FREQ (8000000ul)
/*
* Global data
*/
volatile uint8_t gLEDs_0_to_7;
volatile uint8_t gLEDs_8_to_11;
volatile uint8_t gTicks;
void main(void)
{
/*
* Initialize this PIC
*/
INTCON = 0;
OSCCON = 0x70; /* Select 8MHz system oscillator */
__delay_ms(500); /* Give ISCP device programming tool a chance to get the PICs attention */
TRISA = 0xFF;
TRISC = 0x00;
ANSEL = 0;
OPTION_REG = 0b11000010; /* TIMER0 clock = FOSC/4, prescale 1:8 */
PORTA = 0;
PORTC = 0;
CMCON0 = 7;
TMR0 = 0;
TMR0IF = 0;
TMR0IE = 1;
gLEDs_0_to_7 = 0b00000000;
gLEDs_8_to_11 = 0b00000000;
gTicks = 0;
GIE = 1;
/*
* Initialize ADC on channel 0
*/
ADCON0 = 0;
ADCON1 = 0;
TRISAbits.TRISA0 = 1; /* Make RA0 an input */
ANSELbits.ANS0 = 1; /* Enable AN0 on the RA0 input */
ADCON1bits.ADCS = 0b101; /* Select FOSC/16 as ADC clock source */
ADCON0bits.CHS = 0; /* Select AN0 as ADC input */
ADCON0bits.ADFM = 0; /* Select left justified data */
ADCON0bits.VCFG = 0; /* Select VDD as VREF source */
ADCON0bits.ADON = 1; /* Turn on ADC */
/*
* This is the application loop.
*
* Display 8-bit ADC value in charlieplexed LEDs
*/
while(1)
{
ADCON0bits.GO = 1; /* Start an ADC conversion */
while(ADCON0bits.GO); /* Wait for ADC conversion to finish */
gLEDs_0_to_7 = ADRESH; /* Put High 8-bits of ADC value in LED7 to LED0 */
/* Put Low 2-bits of ADC value in LED8 to LED9 */
gLEDs_8_to_11 = (gLEDs_8_to_11 & ~3) | (ADRESL >> 6);
/* Flash LED D11 to show application is running */
if(!gTicks)
{
gTicks = 250;
gLEDs_8_to_11 ^= 0x08;
}
}
}
/*
* Interrupt handlers
*/
void __interrupt() ISR_handler(void)
{
static uint8_t Timer0Ticks = 0;
static uint8_t State = 8;
uint8_t OutBits, HighBits;
if (TMR0IE && TMR0IF) { /* TIMER0 asserts and interrupt every 1.024 milliseconds */
TMR0IF=0;
if(gTicks != 0) gTicks--;
if (Timer0Ticks == 0) { /* Select another LED every second TIMER0 interrupt */
Timer0Ticks = 1; /* to make LEDs a little brighter make this number larger until you don't like the flickering */
OutBits = 0b00000000;
HighBits = 0b00000000;
switch (--State)
{
case 11:
if (gLEDs_8_to_11 & 0x08)
{
HighBits |= (1 << 1); /* Drive LED11, DRV4=L DRV1=H */
OutBits = ~((1<<1)|(1<<4));
}
break;
case 10:
if (gLEDs_8_to_11 & 0x04)
{
HighBits |= (1 << 4); /* Drive LED10, DRV4=H DRV1=L */
OutBits = ~((1<<1)|(1<<4));
}
break;
case 9:
if (gLEDs_8_to_11 & 0x02)
{
HighBits |= (1 << 1); /* Drive LED9, DRV1=H DRV5=L */
OutBits = ~((1<<1)|(1<<5));
}
break;
case 8:
if (gLEDs_8_to_11 & 0x01)
{
HighBits |= (1 << 5); /* Drive LED8, DRV1=L DRV5=H */
OutBits = ~((1<<1)|(1<<5));
}
break;
case 7:
if (gLEDs_0_to_7 & 0x80)
{
HighBits |= (1 << 1); /* Drive LED7, DRV1=H DRV2=L */
OutBits = ~((1<<1)|(1<<2));
}
break;
case 6:
if (gLEDs_0_to_7 & 0x40)
{
HighBits |= (1 << 2); /* Drive LED6, DRV1=L DRV2=H */
OutBits = ~((1<<1)|(1<<2));
}
break;
case 5:
if (gLEDs_0_to_7 & 0x20)
{
HighBits |= (1 << 2); /* Drive LED5, DRV5=L DRV2=H */
OutBits = ~((1<<5)|(1<<2));
}
break;
case 4:
if (gLEDs_0_to_7 & 0x10)
{
HighBits |= (1 << 5); /* Drive LED4, DRV5=H DRV2=L */
OutBits = ~((1<<5)|(1<<2));
}
break;
case 3:
if (gLEDs_0_to_7 & 0x08)
{
HighBits |= (1 << 2); /* Drive LED3, DRV4=L DRV2=H */
OutBits = ~((1<<4)|(1<<2));
}
break;
case 2:
if (gLEDs_0_to_7 & 0x04)
{
HighBits |= (1 << 4); /* Drive LED2, DRV4=H DRV2=L */
OutBits = ~((1<<4)|(1<<2));
}
break;
case 1:
if (gLEDs_0_to_7 & 0x02)
{
HighBits |= (1 << 5); /* Drive LED1, DRV4=L DRV5=H */
OutBits = ~((1<<4)|(1<<5));
}
break;
default:
if (gLEDs_0_to_7 & 0x01)
{
HighBits |= (1 << 4); /* Drive LED0, DRV4=H DRV5=L */
OutBits = ~((1<<4)|(1<<5));
}
State = 12;
}
TRISA |= ((1<<5)|(1<<4)|(1<<2)|(1<<1)); /* Turn off all LED output drivers */
if (OutBits)
{
PORTA &= OutBits; /* Set both LED drivers to low */
TRISA &= OutBits; /* Turn on LED output drivers */
PORTA |= HighBits; /* Turn on just one of the two LEDs */
}
}
else
{
Timer0Ticks--;
}
}
}
Hope you get a good grade for your home work.
Can someone please help me with this? I have been researching and trying to get this working, but I'm out of luck. All the codes I found online were not working... The output, for now, is 00, 11, 22, 33, ... FF and lop back to 00. How do I separate the first and second digit displays? Like I want it to display from 0 to 255 (00, 01, 02...FF)?
Requirements:
When the circuit is first energized, the seven-segment LEDs will start counting at 0x00.
The duel segment LEDs will count up to 0xFF, increasing by 1 each time. The count MUST BE sequential. It is unacceptable to count 0 to F to 0 on digit 2, then increase digit 1 by 1. The count shall perform like a counter (0x00 to 0x0F then 0x10 etc.).
Once the count reaches 0xFF, the count will start over at 0x00.
The code will contain sufficient delay between incrementing the count so that the count can be visually confirmed that the circuit/code is operating as designed.
The above will occur infinitely, another word, in an endless loop until the device is powered down.
Source code:
#include
void PORTA_init(void)
{
PORTA = 0; // All PORTA Pins are low
CMCON0 = 7; // Turn off Comparators
ANSEL = 0; // Turn off ADC
//TRISA = 0b001111; // RA4 and 5 are outputs; RA0,1,2, and 3 are input
return;
}
/******** END OF PORTA_init ****************************/
/********************************************************
* Notes:
*
* Delay was determined through trial and error
*
* Returns: None
* ********************************************************/
/** Function: main *************************************
*
* Notes:
*
* RA4 - Positive LED Connection for D0
* RA5 - Negative LED Connection for D0
*
* Returns: None -- This routine contains an infinite loop
*
*/
// CONFIG --- Configuration Word --- START
#pragma config FOSC = INTOSCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
// CONFIG --- Configuration Word --- END
int i, j;
int DisplayValue, DisplayLED;
//PLACE LEDDigit ARRAY HERE
const char LEDDigit[] = {
0b0000001, // "0"
0b1001111, // "1"
0b0010010, // "2"
0b0000110, // "3"
0b1001100, // "4"
0b0100100, // "5"
0b0100000, // "6"
0b0001111, // "7"
0b0000000, // "8"
0b0000100, // "9"
0b0001000, // "A"
0b1100000, // "b"
0b0110001, // "C"
0b1000010, // "d"
0b0110000, // "E"
0b0111000}; // "F"
main()
{
PORTA = 0;
PORTC = 0;
CMCON0 = 7; // Turn off Comparators
ANSEL = 0; // Turn off ADC
TRISA = 0b011100;
TRISC = 0b000000;
DisplayValue = 0; // Start Displaying at 0x00
DisplayLED = 0; // Display the 1s first
while(1 == 1) // Loop Forever
{
if (0 == DisplayLED) // True, then display right digit
{
RA5 = LEDDigit[DisplayValue & 0x0F] >> 6;
// Clears display bits 4 - 7 of DisplayValue,
// then selects bit 7 of LEDDigit
PORTC = LEDDigit[DisplayValue & 0x0F] & 0x03F;
// clears display bits 4 - 7 of DisplayValue,
// then selects bits 0 - 6 of LEDDigit
}
else
{
RA5 = LEDDigit[(DisplayValue >> 4) & 0x0F] >> 6;
PORTC = LEDDigit[(DisplayValue >> 4) & 0x0F] & 0x03F;
} //
TRISA = TRISA ^ 0b011111; // Swap Left/Right
PORTA = PORTA & 0b111100; // Make Sure Bits are Low
DisplayLED = DisplayLED ^ 1; // Other Digit Next
NOP(); // Used for 10 ms Timing
for (i = 0; i < 660; i++); // 10 ms Delay Loop
NOP(); // Used for 10 ms Timing
j = j + 1; // Increment the Counter?
if (25 == j) // 1/4 Second Passed?
{
DisplayValue++; // Increment the Counter
j = 0; // Reset for another 1/4 Second
} //
} //
} //
This is a possible answer to your homework assignment:
/*
* File: main.c
* Author: dan1138
* Target: PIC16F688
* Compiler: XC8 v2.00
*
* PIC16F688
* +------------:_:------------+
* GND -> 1 : VDD VSS : 14 <- 5v0
* SEG_An <> 2 : RA5/T1CKI PGD/AN0/RA0 : 13 <> PGD DIGIT_1n
* <> 3 : RA4/AN3 PGC/AN1/RA1 : 12 <> PGC DIGIT_2n
* VPP -> 4 : RA3/VPP AN2/RA2 : 11 <>
* SEG_Bn <> 5 : RC5/RXD AN4/RC0 : 10 <> SEG_Gn
* SEG_Cn <> 6 : RC4/TXD AN5/RC1 : 9 <> SEG_Fn
* SEG_Dn <> 7 : RC3/AN7 AN6 RC2 : 8 <> SEG_En
* +---------------------------:
* DIP-14
*
* Created on July 7, 2019, 6:56 PM
*/
#pragma config FOSC = INTOSCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
#include <xc.h>
#include <stdint.h>
#define _XTAL_FREQ (8000000ul)
const char LEDDigit[] =
{
/* abcdefg _ */
0b00000001, /* | | */
/* |_| */
/* */
0b01001111, /* | */
/* | */
/* _ */
0b00010010, /* _| */
/* |_ */
/* _ */
0b00000110, /* _| */
/* _| */
/* */
0b01001100, /* |_| */
/* | */
/* _ */
0b00100100, /* |_ */
/* _| */
/* _ */
0b00100000, /* |_ */
/* |_| */
/* _ */
0b00001111, /* | */
/* | */
/* _ */
0b00000000, /* |_| */
/* |_| */
/* _ */
0b00001100, /* |_| */
/* | */
/* _ */
0b00001000, /* |_| */
/* | | */
/* */
0b01100000, /* |_ */
/* |_| */
/* _ */
0b00110001, /* | */
/* |_ */
/* */
0b01000010, /* _| */
/* |_| */
/* _ */
0b00110000, /* |_ */
/* |_ */
/* _ */
0b00111000, /* |_ */
/* | */
/* */
0b01111111, /* blank */
/* */
};
volatile uint8_t Digit1Segments;
volatile uint8_t Digit2Segments;
volatile uint8_t Timer0Ticks;
void __interrupt() ISR_handler(void)
{
if (TMR0IE && TMR0IF) { /* TIMER0 asserts and interrupt every 1.024 milliseconds */
TMR0IF=0;
Timer0Ticks++;
if ((Timer0Ticks & 0x0F) == 0) { /* every 16.384 drive a new digit */
if ((TRISA & 3) == 2) {
TRISA |= 3; /* Turn off all digit drivers */
PORTA = 0;
if ((Digit2Segments & (1<<6)) != 0 ) {
PORTA = (1<<5);
}
PORTC = Digit2Segments;
/* Drive digit 2 segments */
TRISA &= ~2;
}
else {
TRISA |= 3;
PORTA = 0;
if ((Digit1Segments & (1<<6)) != 0 ) {
PORTA = (1<<5);
}
PORTC = Digit1Segments;
/* Drive digit 1 segments */
TRISA &= ~1;
}
}
}
}
void main(void) {
uint8_t HexCount;
/*
* Initialize this PIC
*/
INTCON = 0;
OSCCON = 0x70; /* Select 8MHz system oscillator */
__delay_ms(500); /* Give ICSP device programming tool a chance to get the PICs attention */
Digit1Segments = 0b01111111;
Digit2Segments = 0b01111111;
TRISA = 0xDF; /* PORTA bit 5 needs to be an output */
TRISC = 0x00;
ANSEL = 0;
OPTION_REG = 0b11000010; /* TIMER0 clock = FOSC/4, prescale 1:8 */
PORTA = 0;
PORTC = 0;
CMCON0 = 7;
TMR0 = 0;
TMR0IF = 0;
TMR0IE = 1;
GIE = 1;
/*
* This is the application loop.
*
* It counts up one count about every second.
*/
HexCount = 0;
while(1)
{
Digit1Segments = LEDDigit[HexCount & 0x0F];
Digit2Segments = LEDDigit[(HexCount>>4) & 0x0F];
__delay_ms(1000);
HexCount++;
}
}
Only checked using the MPLABX simulator so it may not work in real hardware or in a Proteus simulator.
Warning: I have used concepts that may not have been covered, so if this code works and you hand it in your instructor will know you got it from the internet.
I am working on an MCU where each GPIO port has 16 pins. I have an interrupt routing where I need to see if the input data registers of pins 14, 13 and 12 are high or low. I created this simple test scenario to see if I can read and store that specific pins in a uint8_t variable:
#include <stdio.h>
#include <stdint.h>
#define GPIO_PIN_0 ((uint16_t)0x0001) /* Pin 0 selected */
#define GPIO_PIN_1 ((uint16_t)0x0002) /* Pin 1 selected */
#define GPIO_PIN_2 ((uint16_t)0x0004) /* Pin 2 selected */
#define GPIO_PIN_3 ((uint16_t)0x0008) /* Pin 3 selected */
#define GPIO_PIN_4 ((uint16_t)0x0010) /* Pin 4 selected */
#define GPIO_PIN_5 ((uint16_t)0x0020) /* Pin 5 selected */
#define GPIO_PIN_6 ((uint16_t)0x0040) /* Pin 6 selected */
#define GPIO_PIN_7 ((uint16_t)0x0080) /* Pin 7 selected */
#define GPIO_PIN_8 ((uint16_t)0x0100) /* Pin 8 selected */
#define GPIO_PIN_9 ((uint16_t)0x0200) /* Pin 9 selected */
#define GPIO_PIN_10 ((uint16_t)0x0400) /* Pin 10 selected */
#define GPIO_PIN_11 ((uint16_t)0x0800) /* Pin 11 selected */
#define GPIO_PIN_12 ((uint16_t)0x1000) /* Pin 12 selected */
#define GPIO_PIN_13 ((uint16_t)0x2000) /* Pin 13 selected */
#define GPIO_PIN_14 ((uint16_t)0x4000) /* Pin 14 selected */
#define GPIO_PIN_15 ((uint16_t)0x8000) /* Pin 15 selected */
#define GPIO_PIN_All ((uint16_t)0xFFFF) /* All pins selected */
int main() {
uint32_t maskWithOR = GPIO_PIN_14 | GPIO_PIN_13 | GPIO_PIN_12;
uint32_t maskInBinary = 0b00000000000000000111000000000000;
uint32_t data[8] = {
//.................XXX............
0b10010000100011110000000011111111, //0 = 000
0b10010000100011110001000011111111, //1 = 001
0b10010000100011110010000011111111, //2 = 010
0b10010000100011110011000011111111, //3 = 011
0b10010000100011110100000011111111, //4 = 100
0b10010000100011110101000011111111, //5 = 101
0b10010000100011110110000011111111, //6 = 110
0b10010000100011110111000011111111, //7 = 111
};
printf("maskWithOR = 0x%x\r\n", maskWithOR);
printf("maskInBinary = 0x%x\r\n", maskInBinary);
printf("\r\nOR MASK:\r\n");
for(int i = 0; i < 8; i++) {
uint8_t result = data[i] & maskWithOR;
printf("result[%d] = %d\r\n", i, result);
}
printf("\r\nBINARY MASK:\r\n");
for(int i = 0; i < 8; i++) {
uint8_t result = data[i] & maskInBinary;
printf("result[%d] = %d\r\n", i, result);
}
return 0;
}
This is the output of my test program:
maskWithOR = 0x7000
maskInBinary = 0x7000
OR MASK:
result[0] = 0
result[1] = 0
result[2] = 0
result[3] = 0
result[4] = 0
result[5] = 0
result[6] = 0
result[7] = 0
BINARY MASK:
result[0] = 0
result[1] = 0
result[2] = 0
result[3] = 0
result[4] = 0
result[5] = 0
result[6] = 0
result[7] = 0
What am I doing wrong?
You are storing the result of a 32-bit operation in an 8-bit variable:
uint8_t result = data[i] & maskWithOR;
The result of this operation is that the value is truncated, leaving you with the last eight bits of the original result. Since all three bits of interest to you are above bit 12, the results that you get are always zero.
If you must fit the result in eight bits, shift the value of data[i] & maskWithOR by the index of the lowest bit, i.e. by 12.
You cannot store your AND result in an 8 bit integer...
You could try forcing a boolean result (1 or 0) like this:
uint8_t result = (data[i] & maskWithOR)>0;
After reviewing your desired output value from 0 - 7, you could force a bit shift in your 32 bit unsigned number...12 bits to the right and then mask with only the bits that fit into an 8 bit integer to ensure you get an 8 bit result
uint8_t result = ((data[i] & maskWithOR)>>12) & 255;
Although the 255 mask is a bit redundant...You can do it like this and probably get away with it ...
uint8_t result = (data[i] & maskWithOR)>>12;
But as #chux mentioned ANDing with 255 will quiet or suppress warnings that arise from narrowing the result from uint32_t to uint8_t
In the below you can see whole of my program that is written in Codevision (C language.). When I want to compile it, I receive some errors for Switch blocks! I am pretty sure my block's form are correct! would you please take a look?
*******************************************************
This program was created by the
CodeWizardAVR V3.12 Advanced
Automatic Program Generator
© Copyright 1998-2014 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 12/17/2014
Author :
Company :
Comments:
Chip type : ATmega32
Program type : Application
AVR Core Clock frequency: 8.000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 512
*******************************************************/
#include <mega32.h>
// Standard Input/Output functions
#include <stdio.h>
#include <delay.h>
#include <stdint.h>
// Declare your global variables here
#define SCANS;
void sendNum(int);
void resetWrongTryCounter();
void sendSpecialChars(char);
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
// Place your code here
}
void main(void)
{
// Declare your local variables here
int num=9999;
OSCCAL=0xA0;
// Input/Output Ports initialization
// Port A initialization
// Function: Bit7=Out Bit6=Out Bit5=Out Bit4=Out Bit3=In Bit2=In Bit1=In Bit0=In
DDRA=(1<<DDA7) | (1<<DDA6) | (1<<DDA5) | (1<<DDA4) | (0<<DDA3) | (0<<DDA2) | (0<<DDA1) | (0<<DDA0);
// State: Bit7=1 Bit6=1 Bit5=1 Bit4=1 Bit3=T Bit2=T Bit1=T Bit0=T
PORTA=(1<<PORTA7) | (1<<PORTA6) | (1<<PORTA5) | (1<<PORTA4) | (0<<PORTA3) | (0<<PORTA2) | (0<<PORTA1) | (0<<PORTA0);
// Port B initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRB=(0<<DDB7) | (0<<DDB6) | (0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);
// Port C initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRC=(0<<DDC7) | (0<<DDC6) | (0<<DDC5) | (0<<DDC4) | (0<<DDC3) | (0<<DDC2) | (0<<DDC1) | (0<<DDC0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTC=(0<<PORTC7) | (0<<PORTC6) | (0<<PORTC5) | (0<<PORTC4) | (0<<PORTC3) | (0<<PORTC2) | (0<<PORTC1) | (0<<PORTC0);
// Port D initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRD=(0<<DDD7) | (0<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=0xFF
// OC0 output: Disconnected
TCCR0=(0<<WGM00) | (0<<COM01) | (0<<COM00) | (0<<WGM01) | (0<<CS02) | (0<<CS01) | (0<<CS00);
TCNT0=0x00;
OCR0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=0xFFFF
// OC1A output: Disconnected
// OC1B output: Disconnected
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=0xFF
// OC2 output: Disconnected
ASSR=0<<AS2;
TCCR2=(0<<PWM2) | (0<<COM21) | (0<<COM20) | (0<<CTC2) | (0<<CS22) | (0<<CS21) | (0<<CS20);
TCNT2=0x00;
OCR2=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=(0<<OCIE2) | (0<<TOIE2) | (0<<TICIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (0<<TOIE1) | (0<<OCIE0) | (0<<TOIE0);
// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Low level
// INT1: Off
// INT2: Off
GICR|=(0<<INT1) | (1<<INT0) | (0<<INT2);
MCUCR=(0<<ISC11) | (0<<ISC10) | (0<<ISC01) | (0<<ISC00);
MCUCSR=(0<<ISC2);
GIFR=(0<<INTF1) | (1<<INTF0) | (0<<INTF2);
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: Off
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=(0<<RXC) | (0<<TXC) | (0<<UDRE) | (0<<FE) | (0<<DOR) | (0<<UPE) | (0<<U2X) | (0<<MPCM);
UCSRB=(0<<RXCIE) | (0<<TXCIE) | (0<<UDRIE) | (0<<RXEN) | (1<<TXEN) | (0<<UCSZ2) | (0<<RXB8) | (0<<TXB8);
UCSRC=(1<<URSEL) | (0<<UMSEL) | (0<<UPM1) | (0<<UPM0) | (0<<USBS) | (1<<UCSZ1) | (1<<UCSZ0) | (0<<UCPOL);
UBRRH=0x00;
UBRRL=0x33;
// Analog Comparator initialization
// Analog Comparator: Off
// The Analog Comparator's positive input is
// connected to the AIN0 pin
// The Analog Comparator's negative input is
// connected to the AIN1 pin
ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIC) | (0<<ACIS1) | (0<<ACIS0);
SFIOR=(0<<ACME);
// ADC initialization
// ADC disabled
ADCSRA=(0<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (0<<ADPS2) | (0<<ADPS1) | (0<<ADPS0);
// SPI initialization
// SPI disabled
SPCR=(0<<SPIE) | (0<<SPE) | (0<<DORD) | (0<<MSTR) | (0<<CPOL) | (0<<CPHA) | (0<<SPR1) | (0<<SPR0);
// TWI initialization
// TWI disabled
TWCR=(0<<TWEA) | (0<<TWSTA) | (0<<TWSTO) | (0<<TWEN) | (0<<TWIE);
// Global enable interrupts
#asm("sei")
while (num>-1)
{
resetWrongTryCounter();
delay_ms(100);
sendNum(num/1000);
delay_ms(25);
sendNum((num%1000)/100);
delay_ms(25);
sendNum((num%100)/10);
delay_ms(25);
sendNum(num%10);
delay_ms(500);
--num;
}
}
void sendNum(int num)
{
uint8_t count;
switch(num){
case 0 :
for (count=0; count<SCANS; count++){
while (PINA.0 != 0);
PORTA.5 = 0;
while (PINA.0 != 1);
PORTA.5 = 1;
}
break;
case 1 :
for(count=0;count<SCANS;count++){
while (PINA.1 != 0);
PORTA.4 = 0;
while (PINA.1 != 1);
PORTA.4 = 1;
}
break;
case 2 :
for (count=0; count<SCANS; count++){
while (PINA.2 != 0);
PORTA.4 = 0;
while (PINA.2 != 1);
PORTA.4 = 1;
}
break;
case 3 :
for (count=0; count<SCANS; count++){
while (PINA.3 != 0);
PORTA.4 = 0;
while (PINA.3 != 1);
PORTA.4 = 1;
}
break;
case 4 :
for (count=0; count<SCANS; count++){
while (PINA.1 != 0);
PORTA.5 = 0;
while (PINA.1 != 1);
PORTA.5 = 1;
}
break;
case 5 :
for (count=0; count<SCANS; count++){
while (PINA.2 != 0);
PORTA.5 = 0;
while (PINA.2 != 1);
PORTA.5 = 1;
}
break;
case 6 :
for (count=0; count<SCANS; count++){
while (PINA.3 != 0);
PORTA.5 = 0;
while (PINA.3 != 1);
PORTA.5 = 1;
}
break;
case 7 :
for (count=0; count<SCANS; count++){
while (PINA.1 != 0);
PORTA.6 = 0;
while (PINA.1 != 1);
PORTA.6 = 1;
}
break;
case 8 :
for (count=0; count<SCANS; count++){
while (PINA.2 != 0);
PORTA.6 = 0;
while (PINA.2 != 1);
PORTA.6 = 1;
}
break;
case 9 :
for (count=0; count<SCANS; count++){
while (PINA.3 != 0);
PORTA.6 = 0;
while (PINA.3 != 1);
PORTA.6 = 1;
}
break;
}
}
void sendSpecialChars(char ch)
{
uint8_t count;
switch(ch){
case '*' :
for (count=0; count<SCANS; count++){
while (PINA.0 != 0);
PORTA.4 = 0;
while (PINA.0 != 1);
PORTA.4 = 1;
}
break;
case '#' :
for (count=0; count<SCANS; count++){
while (PINA.0 != 0);
PORTA.6 = 0;
while (PINA.0 != 1);
PORTA.6 = 1;
}
break;
}
}
void resetWrongTryCounter()
{
PORTA.7=0;
delay_ms(50);
PORTA.7=1;
delay_ms(50);
sendNum(4);
sendNum(3);
sendNum(2);
sendNum(1);
sendSpecialChars('#');
}
This is errors that I receive on compile :
Update:
Base on Dear Wintermute's answer, I change the code.
That was right. I change that line to
define SCANS 8;
Most of errors disappear, But these below errors remain :
With
#define SCANS;
I am not surprised that
for (count=0; count<SCANS; count++){
breaks. It expands to
for (count=0; count<;; count++){
which is an invalid expression. You probably want to #define SCANS 100 or some other number.
Addendum: Do not use a semicolon in the macro. It will make SCANS expand to 8;, and you'll be left with
for (count=0; count<8;; count++){
which is also invalid.