I want to write/read data to nand through gpmc from my application in ccs studio (or in QT Creator). What should I do for it? Thank you for your answers.
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
I want to write/read data to nand through gpmc from my application in ccs studio (or in QT Creator). What should I do for it? Thank you for your answers.
Yordan, thank you for your answer. I had done all that you recommended, but now I receive a message
"Unhandled fault: external abort on non-linefetch (0x1818) at 0xaf151040"
in the terminal and
"Bus error "
in QT Creator. Here is my code:
int fp=open("/dev/mem",O_RDWR|O_SYNC);
if (fp<0)
{
cout <<"Cannot open /dev/mem!"<<endl;
return EXIT_FAILURE;
}
volatile uint16_t *gpmc1;
gpmc1=(uint16_t*)mmap(NULL,0x08000000,PROT_READ|PROT_WRITE,MAP_SHARED,fp,0x08000000);
volatile uint32_t * p32 = (uint32_t *) &gpmc1[0x100020];
*p32 = 0x1;
What do you think about it? My gpmc configuration is the following:
gpmc: gpmc@50000000{
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&nandflash_pins_s0>;
ranges = <0 0 0x08000000 0x10000000>; /* CS0: NAND */
nand@0,0 {
reg = <0 0 0>; /* CS0, offset 0 */
nand-bus-width = <8>;
ti,nand-ecc-opt = "bch8";
gpmc,device-nand = "true";
gpmc,device-width = <1>;
gpmc,sync-clk-ps = <0>;
gpmc,cs-on-ns = <0>;
gpmc,cs-rd-off-ns = <44>;
gpmc,cs-wr-off-ns = <44>;
gpmc,adv-on-ns = <6>;
gpmc,adv-rd-off-ns = <34>;
gpmc,adv-wr-off-ns = <44>;
gpmc,we-on-ns = <0>;
gpmc,we-off-ns = <40>;
gpmc,oe-on-ns = <0>;
gpmc,oe-off-ns = <54>;
gpmc,access-ns = <64>;
gpmc,rd-cycle-ns = <82>;
gpmc,wr-cycle-ns = <82>;
gpmc,wait-on-read = "true";
gpmc,wait-on-write = "true";
gpmc,bus-turnaround-ns = <0>;
gpmc,cycle2cycle-delay-ns = <0>;
gpmc,clk-activation-ns = <0>;
gpmc,wait-monitoring-ns = <0>;
gpmc,wr-access-ns = <40>;
gpmc,wr-data-mux-bus-ns = <0>;
#address-cells = <1>;
#size-cells = <1>;
elm_id = <&elm>;
partition@0 {
label = "NAND.SPL";
reg = <0x00000000 0x000020000>;
};
partition@1 {
label = "NAND.SPL.backup1";
reg = <0x00020000 0x00020000>;
};
partition@2 {
label = "NAND.SPL.backup2";
reg = <0x00040000 0x00020000>;
};
partition@3 {
label = "NAND.SPL.backup3";
reg = <0x00060000 0x00020000>;
};
partition@4 {
label = "NAND.u-boot-spl-os";
reg = <0x00080000 0x00040000>;
};
partition@5 {
label = "NAND.u-boot";
reg = <0x000C0000 0x00100000>;
};
partition@6 {
label = "NAND.u-boot-env";
reg = <0x001C0000 0x00020000>;
};
partition@7 {
label = "NAND.u-boot-env.backup1";
reg = <0x001E0000 0x00020000>;
};
partition@8 {
label = "NAND.kernel";
reg = <0x00200000 0x00800000>;
};
partition@9 {
label = "NAND.file-system";
reg = <0x00A00000 0x0F600000>;
};
};
};
Hi,
The unhandled fault message means that you're trying to write to a memory that was not mapped or you haven't enabled GPMC clocks from PRCM.
Probably the gpmc cs address space is differs from the mmapped address space.
To test if your GPMC clocks are enabled you can run devmem2 command on some of the gpmc registers from your console (NOT from your QT application). If you get buss error, then you need to do the GPMC initialization in the QT application.
I am attaching an example use space driver, that I've used some time ago. Have in mind that this setting configures GPMC_CONFIGx registers for NOR like device, you need to modify the settings to match your use case (nand device attached to GPMC):
/* Test file for talking to external memory using GPMC pins in GPMC mode. */ #include <stdio.h> #include <time.h> #include <stdlib.h> #include <stdint.h> #include <fcntl.h> #include <sys/mman.h> #include "hw_gpmc.h" // SYS-BIOS #include "hw_cm_per.h" // SYS-BIOS #include "soc_AM335x.h" // SYS-BIOS #define MMAP_OFFSET 0x44c00000 // redefine HWREG macro to use MMAP result #define HWREG(x) __mmapl[(x-MMAP_OFFSET)/4] #define GPMCREG(x) __mmapl[(x-MMAP_OFFSET + SOC_GPMC_0_REGS )/4] #define CSC_FPGA volatile uint32_t *__mmapl; void gpmc_init_cs(int csNum, int burst_en, int base) { uint16_t clk_divider = 4; uint16_t extra_delay = 0; //cycle 0 is for synchronous reset uint16_t cs_on = 0; uint16_t aad_oe_on = cs_on; uint16_t aad_oe_off = aad_oe_on + 1; //adv is just one low pulse uint16_t aad_adv_on = 0; uint16_t aad_adv_off = aad_oe_off; uint16_t adv_on = aad_adv_off; uint16_t adv_off = adv_on + 1; //write begin uint16_t we_assert = adv_off; uint16_t data_bus = we_assert; uint16_t access_time = 1; //cycles to access each data uint16_t write_access = data_bus + access_time + 1; //when slave reads the data //write end uint16_t write_csoff = write_access + 1; //Rule 7 uint16_t we_deassert = write_csoff; uint16_t write_cycles = write_csoff; //read begin uint16_t oe_assert = adv_off; uint16_t read_access = oe_assert + 2; //When Sitara reads the data //read end uint16_t read_csoff = read_access + 1; //Rule 7 uint16_t oe_deassert = read_csoff; uint16_t read_cycles = read_csoff + 1; //allow OE on RFIC to switch back to address mode uint16_t wait_monitor_delay = 0; // 1 extra clock wait before read uint16_t transaction_delay = 0; uint16_t granularity = 1; #if 0 if (clk_divider == 4) { //granularity doubles RD/WRCYCLETIME, RD/WRACCESSTIME, PAGEBURSTACCESSTIME, CSONTIME, CSRD/WROFFTIME, //ADVONTIME, ADVRD/WROFFTIME, OEONTIME, OEOFFTIME, WEONTIME, WEOFFTIME, //CYCLE2CYCLEDELAY, BUSTURNAROUND, TIMEOUTSTARTVALUE granularity = 2; } #endif //configure for NOR // CONFIG 1 .. 16 bits multiplexed HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG1(csNum)) = (0x0 | ((clk_divider -1) << GPMC_CONFIG1_0_GPMCFCLKDIVIDER_SHIFT) | ((granularity -1) << GPMC_CONFIG1_0_TIMEPARAGRANULARITY_SHIFT) | (0x1 << GPMC_CONFIG1_0_MUXADDDATA_SHIFT ) | (GPMC_CONFIG1_0_DEVICESIZE_SIXTEENBITS << GPMC_CONFIG1_0_DEVICESIZE_SHIFT ) | (0 << GPMC_CONFIG1_0_CLKACTIVATIONTIME_SHIFT) | (wait_monitor_delay << GPMC_CONFIG1_0_WAITMONITORINGTIME_SHIFT) | (0x1 << GPMC_CONFIG1_0_WAITWRITEMONITORING_SHIFT) | (0x1 << GPMC_CONFIG1_0_WAITREADMONITORING_SHIFT) | (0x0 << GPMC_CONFIG1_0_DEVICETYPE_SHIFT) | (2 << GPMC_CONFIG1_0_ATTACHEDDEVICEPAGELENGTH_SHIFT ) | (1 << GPMC_CONFIG1_0_WRITETYPE_SHIFT) | (1 << GPMC_CONFIG1_0_READTYPE_SHIFT) | (burst_en << GPMC_CONFIG1_0_READMULTIPLE_SHIFT) | (burst_en << GPMC_CONFIG1_0_WRITEMULTIPLE_SHIFT) | 0); uint16_t mult = (clk_divider / (granularity)); // config 2 .. chip select assert/deassert times HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG2(csNum)) = (0x0 | ((cs_on * mult) << GPMC_CONFIG2_0_CSONTIME_SHIFT) | // CS_ON_TIME (extra_delay << GPMC_CONFIG2_0_CSEXTRADELAY_SHIFT) | ((read_csoff * mult) << GPMC_CONFIG2_0_CSRDOFFTIME_SHIFT) | // CS_DEASSERT_RD ((write_csoff * mult) << GPMC_CONFIG2_0_CSWROFFTIME_SHIFT)); //CS_DEASSERT_WR // config 3 .. latch enable assert and de-assert HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG3(csNum)) = (0x0 | ((adv_on * mult) << GPMC_CONFIG3_0_ADVONTIME_SHIFT) | //ADV_ASSERT (extra_delay << GPMC_CONFIG3_0_ADVEXTRADELAY_SHIFT) | ((adv_off * mult) << GPMC_CONFIG3_0_ADVRDOFFTIME_SHIFT) | //ADV_DEASSERT_RD ((adv_off * mult) << GPMC_CONFIG3_0_ADVWROFFTIME_SHIFT) | //ADV_DEASSERT_WR ((aad_adv_on * mult) << GPMC_CONFIG3_0_ADVAADMUXONTIME_SHIFT) | ((aad_adv_off * mult) << GPMC_CONFIG3_0_ADVAADMUXRDOFFTIME_SHIFT) | ((aad_adv_off * mult) << GPMC_CONFIG3_0_ADVAADMUXWROFFTIME_SHIFT) | 0); // config 4 .. output enable / read write enable assert and de-assert HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG4(csNum)) = (0x0 | (extra_delay << GPMC_CONFIG4_0_OEEXTRADELAY_SHIFT) | (extra_delay << GPMC_CONFIG4_0_WEEXTRADELAY_SHIFT) | ((oe_assert * mult) << GPMC_CONFIG4_0_OEONTIME_SHIFT) | //OE_ASSERT ((oe_deassert * mult) << GPMC_CONFIG4_0_OEOFFTIME_SHIFT) | //OE_DEASSERT ((we_assert * mult) << GPMC_CONFIG4_0_WEONTIME_SHIFT)| //WE_ASSERT ((we_deassert * mult) << GPMC_CONFIG4_0_WEOFFTIME_SHIFT) | //WE_DEASSERT ((aad_oe_off * mult) << GPMC_CONFIG4_0_OEAADMUXOFFTIME_SHIFT) | ((aad_oe_on * mult) << GPMC_CONFIG4_0_OEAADMUXONTIME_SHIFT) ); // Config 5 - read and write cycle time HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG5(csNum)) = (0x0 | ((read_cycles * mult) << GPMC_CONFIG5_0_RDCYCLETIME_SHIFT)| //CFG_5_RD_CYCLE_TIM XXX ((write_cycles * mult) << GPMC_CONFIG5_0_WRCYCLETIME_SHIFT)| //CFG_5_WR_CYCLE_TIM ((read_access * mult) << GPMC_CONFIG5_0_RDACCESSTIME_SHIFT)| // CFG_5_RD_ACCESS_TIM XXX ((access_time * mult) << GPMC_CONFIG5_0_PAGEBURSTACCESSTIME_SHIFT)); //force write data on rising edge int fix = 1; if (clk_divider == 1) { fix = 0; } // Config 6 .. bus turnaround delay, etc HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG6(csNum)) = (0x0 | (((transaction_delay) ? 1 : 0) << GPMC_CONFIG6_0_CYCLE2CYCLESAMECSEN_SHIFT) | ((transaction_delay * mult) << GPMC_CONFIG6_0_CYCLE2CYCLEDELAY_SHIFT) | ((data_bus * mult) << GPMC_CONFIG6_0_WRDATAONADMUXBUS_SHIFT)| //WR_DATA_ON_ADMUX ((write_access * mult - fix ) << GPMC_CONFIG6_0_WRACCESSTIME_SHIFT)); //CFG_6_WR_ACCESS_TIM // config 7 .. base address of the chip select and address space. HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG7(csNum)) = ( base << 4 << GPMC_CONFIG7_0_BASEADDRESS_SHIFT) | //base address mask (0x1 << GPMC_CONFIG7_0_CSVALID_SHIFT) | //enable (0x0 << GPMC_CONFIG7_0_MASKADDRESS_SHIFT); //256Mb } void gpmc_init() { //enable clock to GPMC module HWREG(SOC_PRCM_REGS + CM_PER_GPMC_CLKCTRL ) |= CM_PER_GPMC_CLKCTRL_MODULEMODE_ENABLE; //check to see if enabled while((HWREG(SOC_PRCM_REGS + CM_PER_GPMC_CLKCTRL) & CM_PER_GPMC_CLKCTRL_IDLEST) != (CM_PER_GPMC_CLKCTRL_IDLEST_FUNC << CM_PER_GPMC_CLKCTRL_IDLEST_SHIFT)); //reset the GPMC module HWREG(SOC_GPMC_0_REGS + GPMC_SYSCONFIG ) |= GPMC_SYSCONFIG_SOFTRESET; while((HWREG(SOC_GPMC_0_REGS + GPMC_SYSSTATUS) & GPMC_SYSSTATUS_RESETDONE) == GPMC_SYSSTATUS_RESETDONE_RSTONGOING); //disable all CSn for (int i = 0; i < 8; i++) { HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG7(i)) = 0; } HWREG(SOC_GPMC_0_REGS + GPMC_SYSCONFIG) = 0x11; HWREG(SOC_GPMC_0_REGS + GPMC_IRQENABLE) = 0x0; HWREG(SOC_GPMC_0_REGS + GPMC_TIMEOUT_CONTROL) = GPMC_TIMEOUT_CONTROL_TIMEOUTSTARTVALUE; #ifndef CSC_FPGA HWREG(SOC_GPMC_0_REGS + GPMC_TIMEOUT_CONTROL) = GPMC_TIMEOUT_CONTROL_TIMEOUTSTARTVALUE | 1; //enable timeout #endif gpmc_init_cs(1, 0, 1); //single @ 0x10000000 (256Mb) gpmc_init_cs(2, 1, 0); //burst @ 0x0 //The first 1MB of address space 0x0-0xFFFFF is inaccessible externally. } uint16_t mymem[0x10000]; void gpmc_dump(int cs) { printf("GPMC_SYSCONFIG=0x%08x\n",GPMCREG(GPMC_SYSCONFIG)); printf("GPMC_TIMEOUT_CONTROL=0x%08x\n",GPMCREG(GPMC_TIMEOUT_CONTROL)); printf("GPMC_IRQENABLE=0x%08x\n",GPMCREG(GPMC_IRQENABLE)); printf("GPMC_CONFIG=0x%08x\n",GPMCREG(GPMC_CONFIG)); printf("CSn=%d....\n", cs); printf("GPMC_CONFIG1_CSn=0x%08x\n", GPMCREG(GPMC_CONFIG1(cs))); printf("GPMC_CONFIG2_CSn=0x%08x\n", GPMCREG(GPMC_CONFIG2(cs))); printf("GPMC_CONFIG3_CSn=0x%08x\n", GPMCREG(GPMC_CONFIG3(cs))); printf("GPMC_CONFIG4_CSn=0x%08x\n", GPMCREG(GPMC_CONFIG4(cs))); printf("GPMC_CONFIG5_CSn=0x%08x\n", GPMCREG(GPMC_CONFIG5(cs))); printf("GPMC_CONFIG6_CSn=0x%08x\n", GPMCREG(GPMC_CONFIG6(cs))); printf("GPMC_CONFIG7_CSn=0x%08x\n", GPMCREG(GPMC_CONFIG7(cs))); } int main(int argc, char** argv) { int fd = open("/dev/mem", O_RDWR|O_SYNC); //O_SYNC makes the memory uncacheable #if 1 __mmapl = (uint32_t*) mmap(NULL, 0x20000000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, MMAP_OFFSET); //gpmc_dump(6); gpmc_init(); gpmc_dump(2); #endif #if 1 volatile uint8_t *extmem; extmem = (uint8_t *) mmap(NULL,0x10000000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x10000000); volatile uint32_t * p32 = (uint32_t *) &extmem[0x100020]; *p32 = 0xdeadbeef; uint32_t val = *p32; *p32 = 0xcafebabe; uint32_t val2 = *p32; printf("val=%#x\n", val); printf("val=%#x\n", val2); //printf("size=%d\n", sizeof(buffer)); //memcpy(extmem, buffer, sizeof(buffer)-1); #endif return(0) ; }
Also revise your pinmux settings.
Hope this helps.
Best Regards,
Yordan
Hi Alex,
You can see an example of nor configuration in: Documentation/devicetree/bindings/mtd/gpmc-nor.txt
But have in mind that the user app will overwrite the timings specified in the dts.
Another example is:
gpmc_pins: pinmux_gpmc_pins { pinctrl-single,pins = < 0x000 0x30 /* gpmc_ad0.gpmc_ad0 MODE0 | INPUT | PULLUP */ 0x004 0x30 /* gpmc_ad1.gpmc_ad1 MODE0 | INPUT | PULLUP */ 0x008 0x30 /* gpmc_ad2.gpmc_ad2 MODE0 | INPUT | PULLUP */ 0x00C 0x30 /* gpmc_ad3.gpmc_ad3 MODE0 | INPUT | PULLUP */ 0x010 0x30 /* gpmc_ad4.gpmc_ad4 MODE0 | INPUT | PULLUP */ 0x014 0x30 /* gpmc_ad5.gpmc_ad5 MODE0 | INPUT | PULLUP */ 0x018 0x30 /* gpmc_ad6.gpmc_ad6 MODE0 | INPUT | PULLUP */ 0x01C 0x30 /* gpmc_ad7.gpmc_ad7 MODE0 | INPUT | PULLUP */ 0x020 0x30 /* gpmc_ad8.gpmc_ad8 MODE0 | INPUT | PULLUP */ 0x024 0x30 /* gpmc_ad9.gpmc_ad9 MODE0 | INPUT | PULLUP */ 0x028 0x30 /* gpmc_ad10.gpmc_ad10 MODE0 | INPUT | PULLUP */ 0x02C 0x30 /* gpmc_ad11.gpmc_ad11 MODE0 | INPUT | PULLUP */ 0x030 0x30 /* gpmc_ad12.gpmc_ad12 MODE0 | INPUT | PULLUP */ 0x034 0x30 /* gpmc_ad13.gpmc_ad13 MODE0 | INPUT | PULLUP */ 0x038 0x30 /* gpmc_ad14.gpmc_ad14 MODE0 | INPUT | PULLUP */ 0x03C 0x30 /* gpmc_ad15.gpmc_ad15 MODE0 | INPUT | PULLUP */ 0x080 0x08 /* gpmc_cscn1.gpmc_cscn1 MODE0 | OUTPUT */ 0x084 0x08 /* gpmc_cscn2.gpmc_cscn2 MODE0 | OUTPUT */ 0x08C 0x28 /* gpmc_clk.gpmc_clk MODE0 | OUTPUT */ 0x090 0x08 /* gpmc_advn_ale.gpmc_advn_ale MODE0 | OUTPUT */ 0x094 0x08 /* gpmc_oen_ren.gpmc_oen_ren MODE0 | OUTPUT */ 0x098 0x08 /* gpmc_wen.gpmc_wen MODE0 | OUTPUT */ 0x070 0x30 /* gpmc_wait0.gpmc_wait0 MODE0 | INPUT | PULLUP */ >; }; &gpmc { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&gpmc_pins>; #address-cells = <2>; #size-cells = <1>; /* chip select ranges */ ranges = <1 0 0x01000000 0x1000000>; ethernet{ reg = <1 0 0x01000000>; /*CSn1*/ bank-width = <2>; /* GPMC_CONFIG1_DEVICESIZE(1) */ /*gpmc,burst-write;*/ /*gpmc,burst-read;*/ /*gpmc,burst-wrap;*/ gpmc,sync-read; /* GPMC_CONFIG1_READTYPE_ASYNC */ gpmc,sync-write; /* GPMC_CONFIG1_WRITETYPE_ASYNC */ gpmc,clk-activation-ns = <0>; /* GPMC_CONFIG1_CLKACTIVATIONTIME(2) */ gpmc,burst-length = <16>; /* GPMC_CONFIG1_PAGE_LEN(2) */ gpmc,mux-add-data = <2>; /* GPMC_CONFIG1_MUXTYPE(2) */ gpmc,sync-clk-ps = <20000>; /* CONFIG2 */ gpmc,cs-on-ns = <0>; gpmc,cs-rd-off-ns = <100>; gpmc,cs-wr-off-ns = <40>; gpmc,adv-on-ns = <0>; /* CONFIG3 */ gpmc,adv-rd-off-ns = <20>; gpmc,adv-wr-off-ns = <20>; gpmc,we-on-ns = <20>; /* CONFIG4 */ gpmc,we-off-ns = <40>; gpmc,oe-on-ns = <20>; gpmc,oe-off-ns = <100>; gpmc,page-burst-access-ns = <20>; /* CONFIG 5 */ gpmc,access-ns = <80>; gpmc,rd-cycle-ns = <120>; gpmc,wr-cycle-ns = <60>; gpmc,wr-access-ns = <40>; /* CONFIG 6 */ gpmc,wr-data-mux-bus-ns = <20>; /*gpmc,bus-turnaround-ns = <40>;*/ /* CONFIG6:3:0 = 4 */ gpmc,cycle2cycle-samecsen; /* CONFIG6:7 = 1 */ gpmc,cycle2cycle-delay-ns = <20>; /* CONFIG6:11:8 = 4 */ /* not using dma engine yet, but we can get the channel number here */ dmas = <&edma 1>; dma-names = "cscdma"; }; };
Best Regards,
Yordan